Underscore.js

Underscore — это невероятно удобная JavaScript-библиотека, этакий швейцарский нож для js-разработчика, набор функций-утилит, которые так привычны любителям Prototype.js (или Ruby). Однако в отличие от Prototype.js, underscore не модифицирует прототипы встроенных объектов JavaScript. Данная особенность гарантирует бесконфликтность, что позволяет замечательно сочетать этот инструмент с, например, jQuery или Backbone, или и тем и другим вместе.

В состав Underscore входит более 80 функций, часть из которых решает более стандартные задачи, например, упрощает работу с коллекциями, а часть позволяет проще делать более экзотические вещи, такие как: функциональное связывание, javascript-шаблонизация, проверки на равенство (напр. объектов), и т.д. Кроме того, Underscore умеет делегировать вызовы, т.е. если код выполняется в современном браузере, который имеет нативные реализации таких методов, как: forEach, map, reduce, filter, every, some и indexOf, то будут вызваны именно они.

Функциональные тесты и тесты производительности прилагаются.

Отлично документированные исходники.

Проект хостится на GitHub. Баг-репорты и фич-реквесты можно разместить тут, или отправить твитом на @documentcloud. Баги по русской версии документации принимаются в этом репозитории.

Underscore — это open-source компонента DocumentCloud.

Файлы для загрузки (правый клик, затем «Сохранить как..»)

Версия для разработчиков (1.6.0) 44kb, много комментариев
Продакшн-версия (1.6.0) < 5.0kb, обфусцированная и сжатая
(Source Map)
Дорелизная версия Используйте на свой страх и риск

Установка

Работа с коллекциями (массивами или объектами)

each_.each(list, iterator, [context]) Alias: forEach
Проходит по всему списку элементов, вызывая для каждого из них функцию iterator, которая будет вызвана в контексте context, если он был передан. При каждом вызове в iterator будут переданы 3 аргумента: (element, index, list). В случае, если list является JavaScript-объектом, то в iterator будут переданы (value, key, list). Если в браузере есть нативная реализация метода forEach, то вызов будет делегирован ему.

_.each([1, 2, 3], function(num){ alert(num); });
// выведет все элементы массива

_.each({one : 1, two : 2, three : 3}, function(num, key){ alert(key+":"+num); });
// выведет содержимое объекта в формате ключ:значение

map_.map(list, iterator, [context]) Alias: collect
Вернёт новый массив, полученный преобразованием каждого элемента list в функции (iterator). Если метод map реализован нативно, будет вызван именно он. Если list — JavaScript-объект, аргументами функции iterator будут
(value, key, list).

_.map([1, 2, 3], function(num){ return num * 3; });
// вернёт [3,6,9]

_.map({one : 1, two : 2, three : 3}, function(num, key){ return num * 3; });
// вернёт [3,6,9]

reduce_.reduce(list, iterator, memo, [context]) Aliases: inject, foldl
Reduce объединит вместе значения из list путём пропускания каждого из них через функцию iterator, которая в качестве аргументов получит
(memo, value, key, list), где memo — начальное значение шага редукции, которое было возвращено предыдущим вызовом iterator.

var sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0);
// вернёт 6

reduceRight_.reduceRight(list, iterator, memo, [context]) Alias: foldr
Правоассоциативная версия reduce. Вызов будет делегирован reduceRight, если есть нативная реализация.

var list = [[0, 1], [2, 3], [4, 5]];

var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
// вернёт [4, 5, 2, 3, 0, 1]

find_.find(list, iterator, [context]) Alias: detect
Вызывает для каждого элемента list функцию сравнения iterator, возвращая первый элемент, для которого iterator вернула true. Выполнение функции при этом прерывается, т.е. вызовов iterator для оставшейся части list не будет.

var even = _.find([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
// вернёт 2

filter_.filter(list, iterator, [context]) Alias: select
Проходит каждое значение list, возвращая массив из значений, для которых iterator вернул true. Делегирует вызов нативной реализации filter, если таковая имеется.

var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
// вернёт [2,4,6]

where_.where(list, properties)
Вернёт массив из элементов list, для которых совпадают значения для соответсвующих ключей, перечисленные в properties.

_.where(listOfPlays, {author: "Shakespeare", year: 1611});

// вернёт
[
    {title: "Cymbeline", author: "Shakespeare", year: 1611},
    {title: "The Tempest", author: "Shakespeare", year: 1611}
]

findWhere_.findWhere(list, properties)
Сработает аналогично where, но вернёт только первый элемент, соответствующий заданным properties.

Если совпадений не найдено или list пустой, то вернёт undefined.

_.findWhere(publicServicePulitzers, {newsroom: "The New York Times"});

// вернёт
{
    year     : 1918,
    newsroom : "The New York Times",
    reason   : "For its public service in publishing in full so many official reports, 
    documents and speeches by European statesmen relating to the progress and 
    conduct of the war."
}

reject_.reject(list, iterator, [context])
Возвращает массив, содержащий все значения list, за исключением элементов, для которых функция iterator вернула значение true. Т.е. reject является «антонимом» filter.

var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
// вернёт [1, 3, 5]

every_.every(list, [predicate], [context]) Alias: all
Вернёт true, если для каждого значения из list predicate вернёт true. Делегирует вызов к нативной реализации every, если она существует.

_.every([true, 1, null, 'yes'], _.identity);
// вернёт false

some_.some(list, [predicate], [context]) Alias: any
Вернёт true, если хотя бы для одного значения из list predicate вернёт true. После нахождения первого удовлетворяющего условию элемента выполнение функции прерывается. Делегирует вызов к нативной реализации some, если она существует.

_.any([null, 0, 'yes', false]);
// вернёт true

contains_.contains(list, value) Alias: include
Вернёт true, если в list содержится элемент, эквивалентный value. Для сравнения используется оператор ===. Если list является массивом, будет вызван метод indexOf.

_.include([1, 2, 3], 3);
// вернёт true

invoke_.invoke(list, methodName, [*arguments])
Вызовет метод methodName на каждом значении list. Все дополнительные аргументы, если они переданы в invoke будут также переданы при вызове methodName.

_.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
// вернёт [[1, 5, 7], [1, 2, 3]]

pluck_.pluck(list, propertyName)
Наверное, наиболее часто используемый метод для map: вернёт массив, состоящий из значений свойства propertyName каждого из элементов list.

var stooges = [{name : 'moe', age : 40}, {name : 'larry', age : 50}, {name : 'curly', age : 60}];
_.pluck(stooges, 'name');
// вернёт ["moe", "larry", "curly"]

max_.max(list, [iterator], [context])
Вернёт максимальное значение из list. Если был передан iterator, то он будет использован для генерация критерия, по которому будет проведено сравнение.

var stooges = [{name : 'moe', age : 40}, {name : 'larry', age : 50}, {name : 'curly', age : 60}];

_.max(stooges, function(stooge){ return stooge.age; });
// вернёт {name : 'curly', age : 60};

min_.min(list, [iterator], [context])
Вернёт минимальное значение из list. Если был передан iterator, то он будет использован для генерации критерия, по которому будет проведено сравнение.

var numbers = [10, 5, 100, 2, 1000];

_.min(numbers);
// вернёт 2

sortBy_.sortBy(list, iterator, [context])
Вернёт отсортированную копию list, сортировка будет проведена по значению, возвращённому функцией iterator для каждого элемента list.

_.sortBy([1, 2, 3, 4, 5, 6], function(num){ return Math.sin(num); });
// вернёт [5, 4, 6, 3, 1, 2]

groupBy_.groupBy(list, iterator)
Разобьёт коллекцию на сеты, сгруппированные по признаку, определённому вызовом iterator для каждого из элементов list. Если iterator не функция, а строка, то группировка будет произведена по значению свойства с именем iterator.

_.groupBy([1.3, 2.1, 2.4], function(num){ return Math.floor(num); });
// вернёт {1: [1.3], 2: [2.1, 2.4]}

_.groupBy(['one', 'two', 'three'], 'length');
// вернёт {3: ["one", "two"], 5: ["three"]}

indexBy_.indexBy(list, iterator, [context])
На вход получает коллекцию list и iterator, функцию, которая возвращает ключ для каждого элемента коллекции (или имя свойства), вернёт объект из пар индекс : соответствующий ему объект. Т.е. работает аналогично groupBy, но для случаев, когда индексы уникальны.

var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}];
_.indexBy(stooges, 'age');

// вернёт
{
  "40": {name: 'moe', age: 40},
  "50": {name: 'larry', age: 50},
  "60": {name: 'curly', age: 60}
}

countBy_.countBy(list, iterator, [context])
Сортирует коллекцию list в группы, вернёт объект, где значением каждого свойства groupName будет количество элементов коллекции, относящихся к этой группе. Т.е. работает аналогично groupBy, но вернёт не сами элементы, а их количество.

_.countBy([1, 2, 3, 4, 5], function(num) {
    return num % 2 == 0 ? 'even': 'odd';
});
// вернёт {odd: 3, even: 2}

shuffle_.shuffle(list)
Вернет перемешанную копию list, используя метод случайного перемешивания Фишера-Ятса.

_.shuffle([1, 2, 3, 4, 5, 6]);
// вернёт [4, 1, 6, 3, 5, 2]

sample_.sample(list, [n])
Вернёт n случайных элементов из списка list. Если n не задан, вернёт 1 случайный элемент.

_.sample([1, 2, 3, 4, 5, 6]);
// вернёт 4


_.sample([1, 2, 3, 4, 5, 6], 3);
// вернёт [1, 6, 2]

toArray_.toArray(list)
Сконвертирует list в массив. Удобен, например, для преобразования объекта arguments.

(function(){ return _.toArray(arguments).slice(0); })(1, 2, 3);
// вернёт [1, 2, 3]

size_.size(list)
Вернёт количество элементов в list.

_.size({one : 1, two : 2, three : 3});
// вернёт 3

Функции для работы с массивами

На заметку: Все описанные ниже функции кроме массивов также будут работать с объектом arguments.

first_.first(array, [n]) Alias: head
Вернёт первый элемент массива array. Если был передан аргумент n, то будет возвращён подмассив из n первых элементов родительского.

_.first([5, 4, 3, 2, 1]);
// вернёт 5

initial_.initial(array, [n])
Вернёт подмассив из всех элементов родительского, за исключением последнего. Довольно полезно при работе с объектом arguments. Если передан n, то возвращённый подмассив не будет содержать n последних элементов родительского.

_.initial([5, 4, 3, 2, 1]);
// вернёт [5, 4, 3, 2]

last_.last(array, [n])
Вернёт последний элемент массива array. Если был передан аргумент n, то будет возвращён подмассив из n последних элементов родительского.

_.last([5, 4, 3, 2, 1]);
// вернёт 1

rest_.rest(array, [index]) Alias: tail
Вернёт все, кроме первого элемента массива. Если передан index то вернёт все элементы, позиция которых больше или равна index.

_.rest([5, 4, 3, 2, 1]);
// вернёт [4, 3, 2, 1]

compact_.compact(array)
Вернёт копию массива array, в котором удалены все «ложные» значения, такие как: false, null, 0, "", undefined и NaN.

_.compact([0, 1, false, 2, '', 3]);
// вернёт [1, 2, 3]

flatten_.flatten(array, [shallow])
Если массив array обладает уровнями вложенности, приведёт его к элементарному виду (вложенность может быть любой глубины). Если аргумент shallow был установлен в true, будет устранён только один уровень вложенности.

_.flatten([1, [2], [3, [[[4]]]]]);
// вернёт [1, 2, 3, 4]

_.flatten([1, [2], [3, [[4]]]], true);
// вернёт [1, 2, 3, [[4]]]

without_.without(array, *values)
Вернёт копию массива array, из которой будут удалены все значения values. Для сравнения будет использован оператор ===.

_.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
// вернёт [2, 3, 4]

partition_.partition(array, predicate)
Разобьёт array на 2: в первом будут содержаться элементы, удовлетворяющие predicate во втором — те, что нет.

_.partition([0, 1, 2, 3, 4, 5], isOdd);
// вернёт [[1, 3, 5], [0, 2, 4]]

union_.union(*arrays)
Объединит уникальные элементы всех массивов arrays. Порядок элементов будет определён порядком их появления в исходных массивах.

_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
// вернёт [1, 2, 3, 101, 10]

intersection_.intersection(*arrays)
Вернёт массив из элементов, встречающихся в каждом из переданных массивов.

_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
// вернёт [1, 2]

difference_.difference(array, *others)
Идентичен without, с той разницей, что значения, которые необходимо исключить, передаются единым массивом other.

_.difference([1, 2, 3, 4, 5], [5, 2, 10]);
// вернёт [1, 3, 4]

uniq_.uniq(array, [isSorted], [iterator]) Alias: unique
Вернёт версию массива array, состоящую только из уникальных элементов. Для сравнения объектов используется оператор ===. Если array был предварительно отсортирован, то это стоит указать, передав true в качестве isSorted, т.к. это значительно повлияет на скорость работы алгоритма. Если Вы желаете определить уникальность элементов после неких преобразований, то задайте функцию iterator, которая их выполнит.

_.uniq([1, 2, 1, 3, 1, 4]);
// вернёт [1, 2, 3, 4]

zip_.zip(*arrays)
Вернёт массив, каждым элементом которого будет массив, содержащий элементы всех переданных массивов (arrays), расположенные на соответствующих позициях. При работе с матрицами zip.apply может быть использован для их транспонирования.

_.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]);
// вернёт [["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]

object_.object(list, [values])
Сконвертирует массивы в объекты. Получает на вход массивы формата
[key, value] или отдельно массив ключей и массив значений. Если ключи дублируются, последнее значение будет результирующим.

_.object(['moe', 'larry', 'curly'], [30, 40, 50]);
// вернёт {moe: 30, larry: 40, curly: 50}

_.object([['moe', 30], ['larry', 40], ['curly', 50]]);
// вернёт {moe: 30, larry: 40, curly: 50}

indexOf_.indexOf(array, value, [isSorted])
Вернёт позицию, на которой находится элемент value в массиве array, или -1, если данный элемент не был найден. Использует нативную реализацию indexOf, если таковая имеется. Если Вы работаете с большим массивом и знаете, что он был предварительно отсортирован, то укажите это, передав true для isSorted, в этом случае будет использован бинарный поиск, который значительно быстрее перебора.

_.indexOf([1, 2, 3], 2);
// вернёт 1

lastIndexOf_.lastIndexOf(array, value, [fromIndex])
Вернёт позицию последнего вхождения элемента value в массиве array, или -1, если данный элемент не был найден. Если это возможно, использует нативную реализацию lastIndexOf. Если передать аргумент fromIndex, поиск будет вестить с этой позиции.

_.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
// вернёт 4

sortedIndex_.sortedIndex(list, value, [iterator], [context])
Использует бинарный поиск, чтобы определить позицию, куда value должен быть вставлен, чтобы не нарушился порядок отсортированного list. Если был передан iterator, он будет использован для вычисления ранга при сортировке каждого из элементов list. Итератор также может быть строкой, т.е. именем свойства, по которому будет проведена сортировка.

_.sortedIndex([10, 20, 30, 40, 50], 35);
// вернёт 3

var stooges = [{name: 'moe', age: 40}, {name: 'curly', age: 60}];
_.sortedIndex(stooges, {name: 'larry', age: 50}, 'age');
// вернёт 1

range_.range([start], stop, [step])
Удобная функция для создания наборов целых чисел, позволяющая их гибкую конфигурацию. Аргумент start, если не передан, по умолчанию будет установлен в 0; step — в 1. Возвращаемый набор будет представлять из себя числа в интервале от start до stop, каждое последующее из которых будет увеличено (или уменьшено) относительно предыдущего на step.

_.range(10);
// вернёт [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

_.range(1, 11); 
// вернёт [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

_.range(0, 30, 5);
// вернёт [0, 5, 10, 15, 20, 25]

_.range(0, -10, -1); 
// вернёт [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]

_.range(0);
// вернёт []

Работа с функциями

bind_.bind(function, object, *arguments)
Связывает функцию function с объектом object. Это значит, что каждый раз когда она будет вызвана this будет указывать на object. Кроме того, можно задать значения параметров по умолчанию, для этого задайте их в arguments, данный приём называется каррингом.

var func = function(greeting){ return greeting + ': ' + this.name };
func = _.bind(func, {name : 'moe'}, 'hi');

func();
// вернёт 'hi: moe'

bindAll_.bindAll(object, *methodNames)
Свяжет с объектом object все методы, переданные как methodNames. Весьма полезно использовать при работе с обработчиками событий. Если methodNames не определены, то все методы самого object будут привязаны к нему.

var buttonView = {
  label   : 'underscore',
  onClick : function(){ alert('clicked: ' + this.label); },
  onHover : function(){ console.log('hovering: ' + this.label); }
};

_.bindAll(buttonView);

jQuery('#underscore_button').bind('click', buttonView.onClick);
// когда на кнопке произойдёт клик, this.label будет содержать значение 'underscore'

partial_.partial(function, *arguments)
Вернёт функцию, которая будет являться function с некоторыми предустановленными аргументами, но без влияния на динамическое изменения контекста (this).

var add = function(a, b) { return a + b; };
add5 = _.partial(add, 5);

add5(10);
// вернёт 15

memoize_.memoize(function, [hashFunction])
Мемоизирует функцию function путём кэширования вычисленного значения. Полезно для ускорения медленных вычислений. Если задана hashFunction, она будет использована для вычисления хэш-ключа, который необходим для хранения результата. По умолчанию hashFunction использует первый аргумент мемоизированной функции в качестве ключа.

var fibonacci = _.memoize(function(n) {
  return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
});

delay_.delay(function, wait, *arguments)
Очень похожа на setTimeout, вызовет function по прошествии заданного (wait) времени в миллисекундах. Если были переданы дополнительные аргументы arguments, они будут переданы в function при её вызове.

var log = _.bind(console.log, console);

_.delay(log, 1000, 'logged later');
// выведет на консоль 'logged later' через секунду после вызова .delay

defer_.defer(function)
Откладывает вызов function до момента, пока не очистится текущий стек вызовов. Аналогична использованию setTimeout с задержкой равной 0. Полезна при затратных с точки зрения производительности вычислениях или рендеринге HTML, чтобы не «замораживать» пользовательский интерфейс на это время.

_.defer(function(){ alert('deferred'); });
// выход из функции будет осуществлён до того, как будет запущена alert.

throttle_.throttle(function, wait, [options])
Вернёт версию функции, которая, при повторных вызовах, исполнится не чаще одного раза в заданный промежуток wait. Полезна для использования при обработке событий, которые происходят слишком часто.

По умолчанию throttle выполнит функцию, как только Вы её вызовете (в первый раз) при последующих вызовах в течение wait выполняться она не будет. Если Вы хотите, чтобы при первоначальном (первый раз) вызове она не выолнялась – нужно передать {leading: false} в качестве options.

var throttled = _.throttle(updatePosition, 100);
$(window).scroll(throttled);

debounce_.debounce(function, wait, [immediate])
Вернёт версию функции, исполнение которой начнётся не ранее, чем истечёт промежуток wait, после её последнего вызова. Полезно для реализации логики, которая зависит от завершения действий пользователя. Например, проверить орфографию комментария пользователя лучше будет после того, как он его окончательно введёт, а динамечески перерассчитать разметку после того, как пользователь закончит изменять размер окна.

Если передать true в качестве аргумента immediate, функция будет выполнена сразу, не дожидаясь прошествия wait. Полезно в случаях, когда нужно предотвратить повторные действия, например, отправку формы.

var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);

once_.once(function)
Вернёт функцию, которая может быть вызвана только один раз. Все последующие её вызовы будут возвращать значение, вычисленное в первый раз. Можно использовать для создания функций-инициализаторов.

var initialize = _.once(createApplication);

initialize();
initialize();
// код будет выполнен единожды

after_.after(count, function)
Вернёт копию функции function, модифицированную таким образом, что она будет запущена только после того, как будет вызвана count раз. Удобно использовать при работе с асинхронными запросами, например, чтобы убедиться, что все обращения к серверу завершились.
Если же указать count равным 0, то function будет вызвана немедленно.

var renderNotes = _.after(notes.length, render);

_.each(notes, function(note) {
  note.asyncSave({success: renderNotes}); 
});
// renderNotes будет вызвана лишь на последней итерации each

wrap_.wrap(function, wrapper)
Передаст функцию function в функцию wrapper, в качестве первого аргумента. Это позволит вызвать её из wrapper в любое удобное время в зависимости от условий.

var hello = function(name) { return "hello: " + name; };
hello = _.wrap(hello, function(func) {
  return "before, " + func("moe") + ", after";
});

hello();
// вернёт 'before, hello: moe, after'

compose_.compose(*functions)
Вернёт функцию, скомпонованную из списка functions, таким образом, что каждая функция будет вызвана с аргументом, значение которого вычислено путём вызова следующей за ней (в аргументах compose) функции. В терминах математики результатом композиции функций f(), g(), и h() будет следующее выражение: f(g(h())).

var greet    = function(name){ return "hi: " + name; };
var exclaim  = function(statement){ return statement + "!"; };
var welcome = _.compose(exclaim, greet);

welcome('moe');
// вернёт 'hi: moe!'

Функции для работы с объектами

keys_.keys(object)
Вернёт массив, состоящий из названий всех свойств object.

_.keys({one : 1, two : 2, three : 3});
// вернёт ["one", "two", "three"]

values_.values(object)
Вернёт массив, состоящий из значений всех свойств object.

_.values({one : 1, two : 2, three : 3});
// вернёт [1, 2, 3]

pairs_.pairs(object)
Сконвертирует объект в набор пар формата[key, value].

_.pairs({one: 1, two: 2, three: 3});
// вернёт [["one", 1], ["two", 2], ["three", 3]]

invert_.invert(object)
Вернёт копию object где ключи — значения, а значения — ключи. Чтобы это заработало, нужно, чтобы все значения свойств объекта могли быть уникально сериализованы в строки.

_.invert({Moe: "Moses", Larry: "Louis", Curly: "Jerome"});
// вернёт {Moses: "Moe", Louis: "Larry", Jerome: "Curly"};

functions_.functions(object) Alias: methods
Вернёт отсортированный массив, состоящий из названий всех методов object.

_.functions(_);
// вернёт ["all", "any", "bind", "bindAll", "clone", "compact", "compose" ...

extend_.extend(destination, *sources)
Скопирует все свойства из объектов source в объект destination. Если объекты source имеют одноименные свойства, то значения каждого будут затёрты значениями из следующего.

_.extend({name : 'moe'}, {age : 50});
// вернёт {name : 'moe', age : 50}

pick_.pick(object, *keys)
Вернёт копию object, где будут значения только для ключей, указанных в keys.

_.pick({name: 'moe', age: 50, userid: 'moe1'}, 'name', 'age');
// вернёт {name: 'moe', age: 50}

omit_.omit(object, *keys)
Вернёт копию object, из которой будут удалены значения по ключам, заданным в keys.

_.omit({name: 'moe', age: 50, userid: 'moe1'}, 'userid');
// вернёт {name: 'moe', age: 50}

defaults_.defaults(object, *defaults)
Проинициализирует неопределённые свойства object значениями одноимённых свойств из defaults. Если же какие-то свойства object уже определены, то они не будут изменены.

var iceCream = {flavor : "chocolate"};

_.defaults(iceCream, {flavor : "vanilla", sprinkles : "lots"});
// вернёт {flavor : "chocolate", sprinkles : "lots"}

clone_.clone(object)
Вернёт клон object. Любые, входящие в его состав массивы или объекты будут скопированы по ссылке, а не продублированы.

_.clone({name : 'moe'});
// вернёт {name : 'moe'}

tap_.tap(object, interceptor)
Вызовет interceptor с object в качестве аргумента и затем вернёт object. Основная задача данного метода — возможность «вклиниться» в цепочку вызовов для того, чтобы произвести некие операции с промежуточными итогами.

_([1,2,3,200]).chain().
  filter(function(num) { return num % 2 == 0; }).
  tap(console.log).
  map(function(num) { return num * num }).
  value();
// на консоль будет выведен массив [2, 200], затем вызов value вернёт [4, 40000]

has_.has(object, key)
Проверяет, есть ли свойство key в объекте object. Для выяснения этого будет вызвана object.hasOwnProperty(key), но при этом будет использована «безопасная» ссылка на hasOwnProperty, подробнее об этом можно прочитать тут.

_.has({a: 1, b: 2, c: 3}, "b");
// true

property_.property(key)
Вернёт функцию, которая, в свою очередь, вернёт значение свойства key для переданного в неё объекта.

var moe = {name: 'moe'};

'moe' === _.property('name')(moe);
// вернёт true

matches_.matches(attrs)
Вернёт функцию, с помощью которой можно будет определить, обладает ли объект нужными свойствами и значениями этих свойств.

var ready = _.matches({selected: true, visible: true});
var readyToGoList = _.filter(list, ready);

isEqual_.isEqual(object, other)
Предоставляет возможность полноценного сравнения двух объектов, т.е. сравнения каждого из их свойств.

var moe   = {name : 'moe', luckyNumbers : [13, 27, 34]};
var clone = {name : 'moe', luckyNumbers : [13, 27, 34]};

moe == clone;
// false

_.isEqual(moe, clone);
// true

isEmpty_.isEmpty(object)
Вернёт true, если object не содержит данных.

_.isEmpty([1, 2, 3]);
// false

_.isEmpty({});
// true

isElement_.isElement(object)
Вернёт true, если object является DOM-элементом.

_.isElement(jQuery('body')[0]);
// true

isArray_.isArray(object)
Вернёт true, если object является массивом (Array).

(function(){ return _.isArray(arguments); })();
// false

_.isArray([1,2,3]);
// true

isObject_.isObject(value)
Вернёт true, если value — объект. Имейте в виду, что в JavaScript массивы и функции — объекты, а строки могут быть как примитивом, так и объектом strings.

_.isObject({});
// true

_.isObject(1);
// false

isArguments_.isArguments(object)
Вернёт true, если object является объектом arguments.

(function(){ return _.isArguments(arguments); })(1, 2, 3);
// true

_.isArguments([1,2,3]);
// false

isFunction_.isFunction(object)
Вернёт true, если object является функцией (Function).

_.isFunction(alert);
// true

isString_.isString(object)
Вернёт true, если object является строкой (String).

_.isString("moe");
// true

isNumber_.isNumber(object)
Вернёт true, если object является числом (Number, включая константу NaN).

_.isNumber(8.4 * 5);
// true

isFinite_.isFinite(object)
Вернёт true, если object является конечным числом и не является Infinite.

_.isFinite(-101);
// true

_.isFinite(-Infinity);
// false

isBoolean_.isBoolean(object)
Вернёт true, если object является булевым значением (true или false).

_.isBoolean(null);
// false

isDate_.isDate(object)
Вернёт true, если object является датой (Date).

_.isDate(new Date());
// true

isRegExp_.isRegExp(object)
Вернёт true, если object является регулярным выражением (RegExp).

_.isRegExp(/moe/);
// true

isNaN_.isNaN(object)
Вернёт true, если object является NaN.
Примечание: разница с нативной функцией isNaN в том, что она также вернёт true для значения undefined.

_.isNaN(NaN);
// true

isNaN(undefined);
// true

_.isNaN(undefined);
// false

isNull_.isNull(object)
Вернёт true, если object является null.

_.isNull(null);
// true

_.isNull(undefined);
// false

isUndefined_.isUndefined(variable)
Вернёт true, если object является undefined.

_.isUndefined(window.missingVariable);
// true

Функции-утилиты

noConflict_.noConflict()
Отвяжет переменную "_" от объекта Underscore. Вернёт ссылку на объект Underscore.

var underscore = _.noConflict();

identity_.identity(value)
Вернёт значение, которое было передано в качестве аргумента (f(x) = x).
Кажется бесполезным, но используется повсюду в Underscore в качестве дефолтного итератора.

var moe = {name : 'moe'};

moe === _.identity(moe);
// true

constant_.constant(value)
Вернёт функцию, которая будет всегда возвращать значение, переданное _.constant, в качестве аргумента.

var moe = {name: 'moe'};

moe === _.constant(moe)();
// true

times_.times(n, iterator)
Вызовет iterator n раз.

_(3).times(function(){ genie.grantWish(); });

random_.random([min], max)
Вернёт случайное целое между min и max включительно. Если передать только один аргумент, то возвращённое целое будет находиться в интервале от 0 до этого числа.

_.random(14, 100);
// 42


_.random(14);
// 12

mixin_.mixin(object)
Позволяет расширять Underscore собственными функциями. Принимает объект следующего вида {name: function}, где name — имя функции, а function — определение.

_.mixin({
  capitalize : function(string) {
    return string.charAt(0).toUpperCase() + string.substring(1).toLowerCase();
  }
});

_("fabio").capitalize();
// вернёт "Fabio"

uniqueId_.uniqueId([prefix])
Сгенерирует уникальный id для, например, DOM-элемента. Если был передан prefix, то сгенерированное имя будет добавлено к нему.

_.uniqueId('contact_');
// вернёт 'contact_104'

escape_.escape(string)
Проэкранирует в строке string спецсимволы (&, <, >, ", ', /), сделав возможным её безболезненную вставку в HTML.

_.escape('Curly, Larry & Moe');
// "Curly, Larry &amp; Moe"

unescape_.unescape(string)
В противоположность escape, заменит &amp;, &lt;, &gt;, &quot;, and &#x27; на их неэкранированные варианты.

_.unescape('Curly, Larry &amp; Moe');
// "Curly, Larry & Moe"

result_.result(object, property)
Если property — функция, она будет вызвана в контексте object; если нет — вернёт его значение.

var object = {cheese: 'crumpets', stuff: function(){ return 'nonsense'; }};

_.result(object, 'cheese');
// "crumpets"

_.result(object, 'stuff');
// "nonsense"

now_.now()
Вернёт текущую метку времени (Integer), используя самую быструю доступную в текущей среде выполнения функцию. Полезно при реализации таймеров/анимаций.

_.now();
// вернёт 1392066795351

template_.template(templateString, [data], [settings])
Компилирует JavaScript-шаблоны в функции, которые могут быть вызваны для рендеринга этого шаблона. Полезно при рендеринге объёмных и сложных частей HTML-разметки из данных JSON. Полученные функции во время обработки данных могут интерполировать переменные, для чего используется следующий синтаксис внутри шаблона: <%= … %>, а также производить вычисления <% … %>. Если вы выводите внутри шаблона данные и хотите, чтобы они были HTML-безопасными (спец. символы будут экранированы), используйте такой синтаксис: <%- … %>. Если при вызове функции-шаблонизатора передать в неё аргумент data, то его свойства будут соответствовать одноимённым свободным переменным внутри функции. Если же передать data во время вызова template, то результатом его работы будет не функция-шаблонизатор, а отрендеренный шаблон.
В скомпилированных функциях сохраняется динамический контекст, так что внутри них можно использовать this.

Передав settings, можно переопределить любые настройки шаблонизатора, определённые в _.templateSettings.

var compiled = _.template("hello: <%= name %>");

compiled({name : 'moe'});
// вернёт "hello: moe"


var list = "<% _.each(people, function(name) { %> <li><%= name %></li> <% }); %>";

_.template(list, {people : ['moe', 'curly', 'larry']});
// вернёт "<li>moe</li><li>curly</li><li>larry</li>"


var template = _.template("<b><%- value %></b>");

template({value : '<script>'});
// вернёт "<b>&lt;script&gt;</b>"

В некоторых случаях вместо <%= ... %> будет лучше использовать print внутри шаблонов.

var compiled = _.template("<% print('Hello ' + epithet); %>");

compiled({epithet: "stooge"});
// вернёт "Hello stooge."

Если по какой-то причине Вам не нравятся дескрипторы, используемые для вывода переменных и вставки исполняемого кода в шаблон, описанные выше, Вы можете изменить настройки шаблонизатора Underscore, чтобы использовать для этих целей привычные символы. Задайте регулярным выражением свойство interpolate, и (необязательно) свойство evaluate для определения участков шаблона, которые должны быть просто выведены в HTML или выполнены, как JavaScript-код. Если же свойство evaluate не было определено, то, используя новые дескрипторы, Вы сможете лишь выводить в HTML значения переменных. В качестве примера можно взглянуть на синтаксис шаблонизатора Mustache.js:

_.templateSettings = {
  interpolate : /\{\{(.+?)\}\}/g
};

var template = _.template("Hello {{ name }}!");

template({name : "Mustache"});
// вернёт "Hello Mustache!"

Цепные вызовы

Вы можете использовать Underscore с применением как объектно-ориентированного подхода, так и процедурного, в зависимости от ваших привычек и предпочтений. В качестве иллюстрации взгляните на 2 строки кода ниже, они выполняют одну и ту же задачу, удваивают каждое число в массиве.

_.map([1, 2, 3], function(n){ return n * 2; });
_([1, 2, 3]).map(function(n){ return n * 2; });

Вызвав chain на объекте, с которым собираетесь работать, вы получите эффект, при котором каждый последующий метод в цепочке будет вызван на объекте, возвращённом предыдущим методом. Чтобы получить результат отработавших методов, нужно вызвать value. Ниже приведён пример цепного вызова map/flatten/reduce, в результате мы получим количество каждого слова в приведённой песне.

var lyrics = [
  {line : 1, words : "I'm a lumberjack and I'm okay"},
  {line : 2, words : "I sleep all night and I work all day"},
  {line : 3, words : "He's a lumberjack and he's okay"},
  {line : 4, words : "He sleeps all night and he works all day"}
];

_.chain(lyrics)
  .map(function(line) { return line.words.split(' '); })
  .flatten()
  .reduce(function(counts, word) {
    counts[word] = (counts[word] || 0) + 1;
    return counts;
}, {}).value();
// вернёт {lumberjack : 2, all : 4, night : 2 ... }

Кроме того, цепочка, сделанная из объекта Underscore, обладает всеми методами стандартного объекта Array, а это значит, что Вы можете её изменить, например, с помощью reverse или push, и затем продолжить работу.

chain_.chain(obj)
Вернёт объект-оболочку, на котором можно будет вызвать любой из методов underscore. Результатом работы вызванных методов будет такой же объект. Для получения результата работы цепочки методов нужно вызвать value.

var stooges = [{name : 'curly', age : 25}, {name : 'moe', age : 21}, {name : 'larry', age : 23}];

var youngest = _.chain(stooges)
  .sortBy(function(stooge){ return stooge.age; })
  .map(function(stooge){ return stooge.name + ' is ' + stooge.age; })
  .first()
  .value(); 
// youngest будет установлена в "moe is 21"

value_(obj).value()
Вернёт значение, извлечённое из объекта-оболочки.

_([1, 2, 3]).value();
// вернёт [1, 2, 3]

Underscore.lua, Lua-порт функций, которые доступны в обоих языках. Включает ООП-обёртки и цепочки. (источник)

Underscore.m, Objective-C-порт многих функций Underscore.js, использующий синтаксис, поощряющий chaining. (источник)

_.m, альтернативный Objective-C-порт, который пытается держаться ближе к оригинальному Underscore.js API. (источник)

Underscore.php, PHP-порт функций, которые доступны в обоих языках. Включает ООП-обёртки и цепочки. (источник)

Underscore-perl, Perl-порт многих функций Underscore.js, нацеленный на хэши и массивы Perl. (источник)

Underscore.cfc, Coldfusion-порт многих функций Underscore.js. (источник)

Underscore.string, расширение Underscore, добавляющее функции манипуляции со строками: trim, startsWith, contains, capitalize, reverse, sprintf и другие.

Модуль Enumerable для Ruby.

Prototype.js, который обеспечивает JavaScript коллекцией функций в манере, близкой к Enumerable в Ruby.

Функциональный JavaScript Оливера Стила, который включает в себя комплексную поддержку функций более высокого порядка, а также строки лямбда.

Data.js Майкла Ауфрайтера, data-манипуляции и persistence-библиотека для JavaScript.

Itertools для Python.

PyToolz, Python-порт, расширяющий itertools и functools, чтобы включить многое из Underscore API.

Change Log

1.6.0February 10, 2014DiffDocs

1.5.2September 7, 2013DiffDocs

1.5.1July 8, 2013DiffDocs

1.5.0July 6, 2013DiffDocs

1.4.4January 30, 2013DiffDocs

1.4.3December 4, 2012DiffDocs

1.4.2October 6, 2012DiffDocs

1.4.1October 1, 2012DiffDocs

1.4.0September 27, 2012DiffDocs

1.3.3April 10, 2012DiffDocs

1.3.1January 23, 2012DiffDocs

1.3.0January 11, 2012DiffDocs

1.2.4Jan. 4, 2012

1.2.3Dec. 7, 2011

1.2.2Nov. 14, 2011

1.2.1Oct. 24, 2011

1.2.0Oct. 5, 2011

1.1.7July 13, 2011
Added _.groupBy, which aggregates a collection into groups of like items. Added _.union and _.difference, to complement the (re-named) _.intersection. Various improvements for support of sparse arrays. _.toArray now returns a clone, if directly passed an array. _.functions now also returns the names of functions that are present in the prototype chain.

1.1.6April 18, 2011
Added _.after, which will return a function that only runs after first being called a specified number of times. _.invoke can now take a direct function reference. _.every now requires an iterator function to be passed, which mirrors the ECMA5 API. _.extend no longer copies keys when the value is undefined. _.bind now errors when trying to bind an undefined value.

1.1.5Mar 20, 2011
Added an _.defaults function, for use merging together JS objects representing default options. Added an _.once function, for manufacturing functions that should only ever execute a single time. _.bind now delegates to the native ECMAScript 5 version, where available. _.keys now throws an error when used on non-Object values, as in ECMAScript 5. Fixed a bug with _.keys when used over sparse arrays.

1.1.4Jan 9, 2011
Improved compliance with ES5's Array methods when passing null as a value. _.wrap now correctly sets this for the wrapped function. _.indexOf now takes an optional flag for finding the insertion index in an array that is guaranteed to already be sorted. Avoiding the use of .callee, to allow _.isArray to work properly in ES5's strict mode.

1.1.3Dec 1, 2010
In CommonJS, Underscore may now be required with just:
var _ = require("underscore"). Added _.throttle and _.debounce functions. Removed _.breakLoop, in favor of an ECMA5-style un-break-able each implementation — this removes the try/catch, and you'll now have better stack traces for exceptions that are thrown within an Underscore iterator. Improved the isType family of functions for better interoperability with Internet Explorer host objects. _.template now correctly escapes backslashes in templates. Improved _.reduce compatibility with the ECMA5 version: if you don't pass an initial value, the first item in the collection is used. _.each no longer returns the iterated collection, for improved consistency with ES5's forEach.

1.1.2
Fixed _.contains, which was mistakenly pointing at _.intersect instead of _.include, like it should have been. Added _.unique as an alias for _.uniq.

1.1.1
Improved the speed of _.template, and its handling of multiline interpolations. Ryan Tenney contributed optimizations to many Underscore functions. An annotated version of the source code is now available.

1.1.0
The method signature of _.reduce has been changed to match the ECMAScript 5 signature, instead of the Ruby/Prototype.js version. This is a backwards-incompatible change. _.template may now be called with no arguments, and preserves whitespace. _.contains is a new alias for _.include.

1.0.4
Andri Möll contributed the _.memoize function, which can be used to speed up expensive repeated computations by caching the results.

1.0.3
Patch that makes _.isEqual return false if any property of the compared object has a NaN value. Technically the correct thing to do, but of questionable semantics. Watch out for NaN comparisons.

1.0.2
Fixes _.isArguments in recent versions of Opera, which have arguments objects as real Arrays.

1.0.1
Bugfix for _.isEqual, when comparing two objects with the same number of undefined keys, but with different names.

1.0.0
Things have been stable for many months now, so Underscore is now considered to be out of beta, at 1.0. Improvements since 0.6 include _.isBoolean, and the ability to have _.extend take multiple source objects.

0.6.0
Major release. Incorporates a number of Mile Frawley's refactors for safer duck-typing on collection functions, and cleaner internals. A new _.mixin method that allows you to extend Underscore with utility functions of your own. Added _.times, which works the same as in Ruby or Prototype.js. Native support for ECMAScript 5's Array.isArray, and Object.keys.

0.5.8
Fixed Underscore's collection functions to work on NodeLists and HTMLCollections once more, thanks to Justin Tulloss.

0.5.7
A safer implementation of _.isArguments, and a faster _.isNumber,
thanks to Jed Schmidt.

0.5.6
Customizable delimiters for _.template, contributed by Noah Sloan.

0.5.5
Fix for a bug in MobileSafari's OOP-wrapper, with the arguments object.

0.5.4
Fix for multiple single quotes within a template string for _.template. See: Rick Strahl's blog post.

0.5.2
New implementations of isArray, isDate, isFunction, isNumber, isRegExp, and isString, thanks to a suggestion from Robert Kieffer. Instead of doing Object#toString comparisons, they now check for expected properties, which is less safe, but more than an order of magnitude faster. Most other Underscore functions saw minor speed improvements as a result. Evgeniy Dolzhenko contributed _.tap, similar to Ruby 1.9's, which is handy for injecting side effects (like logging) into chained calls.

0.5.1
Added an _.isArguments function. Lots of little safety checks and optimizations contributed by Noah Sloan and Andri Möll.

0.5.0
[API Changes] _.bindAll now takes the context object as its first parameter. If no method names are passed, all of the context object's methods are bound to it, enabling chaining and easier binding. _.functions now takes a single argument and returns the names of its Function properties. Calling _.functions(_) will get you the previous behavior. Added _.isRegExp so that isEqual can now test for RegExp equality. All of the "is" functions have been shrunk down into a single definition. Karl Guertin contributed patches.

0.4.7
Added isDate, isNaN, and isNull, for completeness. Optimizations for isEqual when checking equality between Arrays or Dates. _.keys is now 25%–2X faster (depending on your browser) which speeds up the functions that rely on it, such as _.each.

0.4.6
Added the range function, a port of the Python function of the same name, for generating flexibly-numbered lists of integers. Original patch contributed by Kirill Ishanov.

0.4.5
Added rest for Arrays and arguments objects, and aliased first as head, and rest as tail, thanks to Luke Sutton's patches. Added tests ensuring that all Underscore Array functions also work on arguments objects.

0.4.4
Added isString, and isNumber, for consistency. Fixed _.isEqual(NaN, NaN) to return true (which is debatable).

0.4.3
Started using the native StopIteration object in browsers that support it. Fixed Underscore setup for CommonJS environments.

0.4.2
Renamed the unwrapping function to value, for clarity.

0.4.1
Chained Underscore objects now support the Array prototype methods, so that you can perform the full range of operations on a wrapped array without having to break your chain. Added a breakLoop method to break in the middle of any Underscore iteration. Added an isEmpty function that works on arrays and objects.

0.4.0
All Underscore functions can now be called in an object-oriented style, like so: _([1, 2, 3]).map(...);. Original patch provided by Marc-André Cournoyer. Wrapped objects can be chained through multiple method invocations. A functions method was added, providing a sorted list of all the functions in Underscore.

0.3.3
Added the JavaScript 1.8 function reduceRight. Aliased it as foldr, and aliased reduce as foldl.

0.3.2
Now runs on stock Rhino interpreters with: load("underscore.js"). Added identity as a utility function.

0.3.1
All iterators are now passed in the original collection as their third argument, the same as JavaScript 1.6's forEach. Iterating over objects is now called with (value, key, collection), for details see _.each.

0.3.0
Added Dmitry Baranovskiy's comprehensive optimizations, merged in Kris Kowal's patches to make Underscore CommonJS and Narwhal compliant.

0.2.0
Added compose and lastIndexOf, renamed inject to reduce, added aliases for inject, filter, every, some, and forEach.

0.1.1
Added noConflict, so that the "Underscore" object can be assigned to other variables.

0.1.0
Initial release of Underscore.js.

A DocumentCloud Project