Underscore.js
![]() | |
Разработчик(и) | Джереми Ашкенас , Джулиан Гонгриджп |
---|---|
Первоначальный выпуск | 28 октября 2009 г [1] |
Стабильная версия | 1.13.6
/ 24 сентября 2022 г |
Репозиторий | |
Написано в | JavaScript |
Размер | Производство 7,5 КБ 68 КБ разработки |
Тип | библиотека JavaScript |
Лицензия | С |
Веб-сайт | подчеркнутый |
Underscore.js — это библиотека JavaScript , предоставляющая служебные функции для распространенных задач программирования. [2] Он сравним с функциями, предоставляемыми Prototype.js и языком Ruby , но в нем используется дизайн функционального программирования вместо расширения прототипов объектов . В документации Underscore.js называется «связующим звеном со jQuery смокингом и подтяжками Backbone.js ». Underscore.js был создан Джереми Ашкенасом , который также известен своими Backbone.js и CoffeeScript . [3]
История
[ редактировать ]Джереми Ашкенас создал Underscore к концу 2009 года как ответвление проекта DocumentCloud вместе с Backbone.js . Это была одна из первых библиотек для JavaScript, предоставляющая общие утилиты функционального программирования, вдохновленная Prototype.js , Functional JavaScript Оливера Стила и Micro-Templating Джона Резига. [4]
В 2012 году Джон-Дэвид Далтон создал форк Underscore под названием Lo-Dash (ныне Lodash ). Первоначально Lo-Dash рекламировался как альтернатива Underscore с «последовательностью, настройкой, производительностью и дополнительными возможностями». [5] Тем не менее, Lodash уже на ранней стадии отошел от оригинального интерфейса Underscore. [6] и начал вносить более радикальные изменения в выпуске 3.0.0, в результате чего пользователям Lodash пришлось менять свой код. [7]
В мае 2015 года Джереми Ашкенас объявил, что Джон-Дэвид Далтон связался с ним по поводу объединения библиотек. Несмотря на опасения по поводу стиля и размера кода, Ашкенас не был против объединения некоторых расширений Lodash с Underscore. [8] В то время несколько разработчиков параллельно работали над Underscore и Lodash; эта группа участников начала вносить изменения в Underscore, чтобы сделать его более похожим на Lodash. [9]
Однако параллельно с этими усилиями Далтон внес более радикальные изменения в интерфейс Lodash. В июне 2015 года он анонсировал версию Lodash 4.0.0, которая еще больше отдалила Lodash от интерфейса Underscore, а также значительно отклонилась от серии версии 3.x самого Lodash. [10] [11] Это побудило некоторые проекты, зависевшие от Lodash, создать свои собственные дистрибутивы Lodash 3. [12]
В феврале 2016 года Далтон объявил, что считает слияние завершенным. Он предложил пользователям перейти с Underscore на Lodash, мотивируя это статистикой доли использования. [13] Однако сопровождающий Underscore ясно дал понять, что не намерен прекращать разработку Underscore как отдельной библиотеки. [14] После 2016 года обе библиотеки вошли в состояние низкой активности развития. [15] [16]
Со временем в новые версии стандарта ECMAScript были добавлены встроенные функции, которые копируют некоторые функции Underscore, такие как Object.assign
и Array.prototype.map
. Однако встроенные функции иногда менее эффективны, чем их эквиваленты Underscore; в частности, встроенные методы итерации массива, такие как map
, filter
и forEach
не может перебирать простые объекты и не поддерживает сокращения итерируемых . [17] [18] [19] [20] [21] [22]
По состоянию на март 2021 года Underscore активно разрабатывает Джулиан Гонгриджп, который начал вносить значительный вклад в марте 2020 года. [15] Библиотека по-прежнему широко используется, и ее загружают с npm несколько миллионов раз каждую неделю. [23]
Содержание
[ редактировать ]По сути, Underscore обеспечивает три вещи:
- Коллекция из более чем 100 повторно используемых функций, которые призваны быть практически полезными в повседневных приложениях. В документации различают несколько категорий:
- Функции сбора, такие как
find
,map
,min
/max
,groupBy
иshuffle
обрабатывать коллекции данных. Эти функции могут работать как с элементами массивоподобных последовательностей, так и со свойствами объектов. - Функции массива, такие как
first
/last
,flatten
,chunk
иzip
работать исключительно с объектами, подобными массивам. - Функциональные функции, такие как
bind
,memoize
,partial
иdebounce
принять функцию в качестве аргумента и вернуть новую функцию с измененными свойствами ( функции высшего порядка ). - Функции объекта — это более фундаментальная категория, содержащая множество функций, которые также повторно используются внутри Underscore. [24] Его можно условно разделить на две подкатегории:
- Функции типового тестирования, такие как
isNumber
,isElement
иisDataView
. - Такие функции, как
keys
,extend
,pick
/omit
,pairs
иinvert
, которые манипулируют (простыми) объектами как данными.
- Функции типового тестирования, такие как
- Функции полезности — это категория отдыха. Среди прочего, он включает тривиальные функции
identity
иnoop
и функции манипулирования строкамиescape
,unescape
иtemplate
. В эту категорию также входят функцииiteratee
иmixin
, которые можно считать специальными объектами, как указано в пункте 2.
- Функции сбора, такие как
- Специальные помещения, такие как
chain
иiteratee
, которые объединяются с функциями из пункта 1, чтобы обеспечить более короткий и понятный синтаксис. Специальная функция_
, в честь которого названа библиотека, занимает центральное место в этих учреждениях. - Грамотный исходный код, предназначенный для чтения, чтобы можно было легко отслеживать реализацию библиотеки. Документация включает визуализированную версию исходного кода, где комментарии находятся слева, а логика — справа. Комментарии форматируются с использованием Markdown , а логика имеет подсветку синтаксиса . Начиная с версии 1.11, Underscore является модульным . По этой причине документация теперь включает как модульную версию аннотированного исходника, в которой каждая функция находится на отдельной странице, так и
import
Ссылки представляют собой кликабельные гиперссылки и единственную версию для чтения , где все функции находятся на одной странице в порядке зависимости .
Обзор и примеры функций
[ редактировать ]Подчеркивание продвигает функциональный стиль , в котором несколько функций могут быть объединены в одном выражении для получения новой функциональности. Например, в следующем выражении используются две функции подчеркивания для группировки слов по первым символам:
import { groupBy, first } from 'underscore';
groupBy(['avocado', 'apricot', 'cherry', 'date', 'durian'], first);
// result:
// { a: ['avocado', 'apricot'],
// c: ['cherry'],
// d: ['date', 'durian']
// }
Функции подчеркивания никоим образом не отличаются от пользовательских функций. Если бы пользователь реализовал свой собственный first
функции, приведенное выше выражение работало бы одинаково хорошо:
import { groupBy } from 'underscore';
const first = array => array[0];
groupBy(['avocado', 'apricot', 'cherry', 'date', 'durian'], first);
Однако набор функций, предоставляемых Underscore, специально выбран для минимизации таких усилий, чтобы пользователь мог создавать функциональность из существующих функций, а не писать свои собственные.
Функции, которые перебирают содержимое массива или объекта, обычно принимают данные в качестве первого параметра, а итерирующую функцию или итерируемого объекта — в качестве второго параметра. В приведенном выше примере first
передается ли итерируемый объект groupBy
.
Хотя от итератора не требуется их использовать, в большинстве случаев он получает три аргумента: (1) значение в текущей позиции в коллекции, (2) ключ или индекс этого значения и (3) всю коллекцию. В следующем примере второй аргумент используется в итерации для pick
чтобы выбрать только свойства объекта, ключ которого начинается с заглавной буквы:
import { pick } from 'underscore';
const details = {
Official: 'Wolfgang Amadeus Mozart',
informal: 'Wolfie'
};
const keyIsUpper = (value, key) => key[0] === key[0].toUpperCase();
pick(details, keyIsUpper);
// {Official: 'Wolfgang Amadeus Mozart'}
Многие функции Underscore можно использовать в качестве итерации, как показано ранее на примере first
. Кроме того, есть несколько распространенных случаев, когда пользователь может избежать написания итеративной функции, используя вместо этого сокращенную итерируемую функцию . В следующем примере строка 'name'
используется как сокращение для итерации, чтобы извлечь все name
свойства из массива объектов:
import { map } from 'underscore';
const people = [
{name: 'Lily', age: 44, occupation: 'librarian'},
{name: 'Harold', age: 10, occupation: 'dreamer'},
{name: 'Sasha', age: 68, occupation: 'library developer'}
];
map(people, 'name'); // ['Lily', 'Harold', 'Sasha']
Все функции категории «коллекция», включая groupBy
и map
функции, продемонстрированные выше, могут перебирать как индексы массива, так и ключи объекта. Это показано ниже с помощью reduce
:
import { reduce } from 'underscore';
const add = (a, b) => a + b;
const sum = numbers => reduce(numbers, add, 0);
sum([11, 12, 13]); // 36
sum({Alice: 9, Bob: 9, Clair: 7}); // 25
Помимо функций, которые перебирают массивы или объекты, Underscore предоставляет широкий спектр других функций многократного использования. Например, throttle
ограничивает частоту, с которой оценивается функция:
import { throttle } from 'underscore';
// The scroll event triggers very often, so the following line may
// slow down the browser.
document.body.addEventListener('scroll', expensiveUpdateFunction);
// Limit evaluation to once every 100 milliseconds.
const throttledUpdateFunction = throttle(expensiveUpdateFunction, 100);
// Much smoother user experience!
document.body.addEventListener('scroll', throttledUpdateFunction);
Другой пример: defaults
, который присваивает свойства объекта, только если они еще не установлены:
import { defaults } from 'underscore';
const requestData = {
url: 'wikipedia.org',
method: 'POST',
body: 'article text'
};
const defaultFields = {
method: 'GET',
headers: {'X-Requested-With': 'XMLHttpRequest'}
};
defaults(requestData, defaultFields);
// {
// url: 'wikipedia.org',
// method: 'POST',
// body: 'article text',
// headers: {'X-Requested-With': 'XMLHttpRequest'}
// }
The _
функция
[ редактировать ] Подчеркивание получило свое название от функции _
, который служит нескольким целям.
Функция-обертка
[ редактировать ]Как функция, _
возвращает завернутую версию любого значения, переданного в качестве первого аргумента. Этот специальный объект имеет все функции Underscore в качестве методов, что позволяет использовать другую нотацию, называемую «стилем ООП»:
import _, { last } from 'underscore';
// "Normal" or "functional" style
last([1, 2, 3]); // 3
// "OOP style"
_([1, 2, 3]).last() // 3
Эта функция используется при цепочке ( следующий раздел ). Значение можно снова развернуть с помощью .value()
метод для дальнейшей обработки за пределами Underscore. В некоторых случаях значения также разворачиваются автоматически.
// Explicit unwrap
_([1, 2, 3]).value() // [1, 2, 3]
// Automatic unwrap when coerced to number
1 + _(2) // 3
// Automatic unwrap when coerced to string
'abc' + _('def') // 'abcdef'
// Automatic unwrap when formatted as JSON
JSON.stringify({ a: _([1, 2]) }) // '{"a":[1,2]}'
Частичный заполнитель приложения
[ редактировать ]_
также выступает в качестве заполнителя для partial
функция. partial
создает частично примененную версию функции и _
можно использовать, чтобы оставить некоторые параметры «открытыми», чтобы их можно было указать позже. Например, groupBy
Пример из обзора можно расширить следующим образом, чтобы превратить выражение в функцию многократного использования:
import _, { partial, groupBy, first } from 'underscore';
const groupByFirstChar = partial(groupBy, _, first);
groupByFirstChar(['avocado', 'apricot', 'cherry', 'date', 'durian']);
// { a: ['avocado', 'apricot'],
// c: ['cherry'],
// d: ['date', 'durian']
// }
groupByFirstChar(['chestnut', 'pistache', 'walnut', 'cashew']);
// { c: ['chestnut', 'cashew'],
// p: ['pistache'],
// w: ['walnut]
// }
Точка настройки
[ редактировать ]Более того, _
служит центральной точкой настройки , где пользователи могут настроить поведение функций Underscore в соответствии со своими потребностями. В частности, пользователи могут переопределить _.iteratee
для создания новых сокращений итеративных элементов и _.templateSettings
для того, чтобы настроить template
функция.
Дескриптор пространства имен
[ редактировать ]В более общем плане все функции подчеркивания присутствуют как свойства на _
, например, также _.map
и _.debounce
. Это дает возможность использовать _
как дескриптор пространства имен . С появлением модулей в ES6 наличие такого дескриптора пространства имен больше не является строго необходимым, но такая практика по-прежнему часто встречается в коде, использующем старые модульные системы, такие как AMD и CommonJS :
var _ = require('underscore');
_.groupBy(['avocado', 'apricot', 'cherry', 'date', 'durian'], _.first);
Учитывая существующую практику, это также может быть удобной записью, чтобы уточнить, что имеется в виду функция именно из библиотеки Underscore, а не функция с таким же именем из другой библиотеки. Например, и Underscore, и Async предоставляют функцию с именем each
; чтобы различать их, можно написать _.each
и async.each
, соответственно.
Цепочка
[ редактировать ]Функция chain
может использоваться для создания модифицированной версии оболочки, созданной _
функция . При вызове такой связанной оболочки каждый метод возвращает новую обертку, чтобы пользователь мог продолжать обрабатывать промежуточные результаты с помощью функций Underscore:
import { chain } from 'underscore';
const square = x => x * x;
const isOdd = x => x % 2;
chain([1, 2, 3, 4]).filter(isOdd).map(square).last()
// returns a wrapper of 9
Нередко функция, реализованная с помощью Underscore, полностью состоит из return
утверждение с цепочкой, заканчивающейся на .value()
:
const add = (x, y) => x + y;
// Given an array of numbers, return the sum of the squares of
// those numbers. This could be used in a statistics library.
function sumOfSquares(numbers) {
return chain(numbers)
.map(square)
.reduce(add)
.value();
}
Объединение в цепочки не является исключительным для функций, поставляемых с Underscore. Пользователи также могут включить цепочку для своих собственных функций, передав их в mixin
функция:
import { reduce, mixin } from 'underscore';
const sum = numbers => reduce(numbers, add, 0);
mixin({ sum, square });
chain([1, 2, 3]).map(square).sum().value(); // 14
chain([1, 2, 3]).sum().square().value(); // 36
Фактически, именно так цепочка включается и для собственных функций Underscore. Все функции Underscore пишутся как обычные автономные функции, без какой-либо специальной подготовки к связыванию, а затем «примешиваются» к _
функционировать впоследствии. [25]
Итеративные сокращения
[ редактировать ]Как упоминалось ранее в обзоре , большинство функций Underscore, которые перебирают массивы или объекты, принимают сокращенную запись как итерируемый, а не функцию. Повторяем пример из этого раздела здесь:
import { map } from 'underscore';
const people = [
{name: 'Lily', details: {age: 44, occupation: 'fire fighter'}},
{name: 'Harold', details: {age: 10, occupation: 'dreamer'}},
{name: 'Sasha', details: {age: 68, occupation: 'library developer'}}
];
map(people, 'name'); // ['Lily', 'Harold', 'Sasha']
На самом деле эта запись активируется путем передачи сокращенного значения через _.iteratee
чтобы получить функцию. _.iteratee
по умолчанию используется iteratee
функция, которая поставляется с подчеркиванием, которое, в зависимости от значения, возвращает функцию следующим образом.
Пути
[ редактировать ]Если значение представляет собой строку, iteratee
пересылает значение в property
, который интерпретирует строку как ключ свойства. Он возвращает функцию, которая пытается извлечь свойство с заданным ключом из своего аргумента. Следующие выражения эквивалентны:
import { iteratee, property } from 'underscore';
map(people, 'name');
map(people, iteratee('name'));
map(people, property('name'));
map(people, obj => obj && obj['name']);
// ['Lily', 'Harold', 'Sasha']
Массивы и числа также передаются в property
. Массивы можно использовать для получения вложенных свойств:
map(people, ['details', 'occupation']);
// ['fire fighter', 'dreamer', 'library developer']
Числа могут использоваться как индексы массивов и строк. Объединив все это, мы можем использовать следующее выражение, чтобы подсчитать, сколько раз буквы алфавита встречаются в качестве второго символа профессии человека:
import { countBy } from 'underscore';
countBy(people, ['details', 'occupation', 1]); // {i: 2, r: 1}
Хэши атрибутов
[ редактировать ]Когда значение является объектом, iteratee
пересылает его matcher
, который интерпретирует объект как набор атрибутов, которые должны быть сопоставлены. Он возвращает функцию, которая вернет true
или false
в зависимости от того, имеет ли его аргумент тот же набор атрибутов.
import { find } from 'underscore';
find(people, {name: 'Sasha'});
// {name: 'Sasha', details: {age: 68, occupation: 'library developer'}}
find(people, {name: 'Walter'});
// undefined
null
и undefined
[ редактировать ] Когда значение null
или undefined
, iteratee
возвращает функцию идентификации , которую Underscore экспортирует как identity
. Это можно использовать для фильтрации истинных значений из коллекции:
import { filter, iteratee, identity } from 'underscore';
const example = [0, 1, '', 'abc', true, false, {}];
// The following expressions are all equivalent.
filter(example);
filter(example, undefined);
filter(example, iteratee(undefined));
filter(example, identity);
// [1, 'abc', true, {}]
Переопределение _.iteratee
[ редактировать ] Пользователи могут переопределить _.iteratee для создания собственных сокращений. Следующий пример иллюстрирует, как это можно использовать для реализации фильтрации регулярных выражений:
import {
iteratee as originalIteratee,
isRegExp,
mixin,
filter,
} from 'underscore';
function iteratee(value, context) {
if (isRegExp(value)) {
return string => value.test(string);
} else {
return originalIteratee(value, context);
}
}
mixin({iteratee});
filter(['absolutely', 'amazing', 'fabulous', 'trousers'], /ab/);
// ['absolutely', 'fabulous']
См. также
[ редактировать ]Ссылки
[ редактировать ]- ^ Версия 0.1.0 , jashkenas/underscore, GitHub
- ^ «Underscore.js — небольшой фреймворк с акцентом» . entwicklung.de (на немецком языке). 20 июня 2018 г. Проверено 9 июля 2020 г.
- ^ «JavaScript Meetup City» , открытое издание , The New York Times , 4 апреля 2012 г.
- ^ Ашкенас, Джереми. «Подчеркнуть источник 0.4.0» . cdn.rawgit.com . Проверено 1 марта 2021 г.
- ^ «Ло-Дэш v2.2.1» . lodash.com . Архивировано из оригинала 6 ноября 2013 года . Проверено 1 марта 2021 г.
{{cite web}}
: CS1 maint: неподходящий URL ( ссылка ) - ^ «Журнал изменений Lodash — 1.0.0 rc1» . github.com . 4 декабря 2012 года . Проверено 1 марта 2021 г.
- ^ «Журнал изменений Лодаша — 3.0.0» . github.com . 26 января 2015 года . Проверено 1 марта 2021 г.
- ^ Ашкенас, Джереми (21 мая 2015 г.). «Большая Кахуна: тема слияния Underscore + Lodash» . github.com . Проверено 1 марта 2021 г.
- ^ «Подчеркивание: объединенные запросы на включение с критическими изменениями в период с 21 мая по 1 октября 2015 г.» . github.com . Проверено 1 марта 2021 г.
- ^ Далтон, Джон-Дэвид (8 июня 2015 г.). «комментарий к «Core API» » . github.com . Проверено 1 марта 2021 г.
- ^ «Журнал изменений Lodash 4.0.0» . github.com . 12 января 2016 года . Проверено 1 марта 2021 г.
- ^ "@sailshq/lodash" . npmjs.com . Проверено 1 марта 2021 г.
- ^ Далтон, Джон-Дэвид (13 февраля 2016 г.). «Объединить обновление» . github.com . Проверено 1 марта 2021 г.
- ^ Кребс, Адам (17 февраля 2016 г.). «прокомментируйте «Объединить обновление». " . github.com . Проверено 1 марта 2021 г.
- ^ Перейти обратно: а б "jashkenas/подчеркивание. Информация: участники" . github.com . Проверено 1 марта 2021 г.
- ^ "lodash/lodash Insight: Участники" . github.com . Проверено 1 марта 2021 г.
- ^ «Массив.прототип.карта» . http://developer.mozilla.org . Проверено 1 марта 2021 г.
- ^ «Массив.прототип.фильтр» . http://developer.mozilla.org . Проверено 1 марта 2021 г.
- ^ "Array.prototype.forEach" . http://developer.mozilla.org . Проверено 1 марта 2021 г.
- ^ "_.карта" . underscorejs.org . Проверено 1 марта 2021 г.
- ^ "_.фильтр" . underscorejs.org . Проверено 1 марта 2021 г.
- ^ "_.каждый" . underscorejs.org . Проверено 1 марта 2021 г.
- ^ «подчеркивание» . npmjs.com . Проверено 1 марта 2021 г.
- ^ Гонгриджп, Джулиан. "модули/index.js" . underscorejs.org . Проверено 5 марта 2021 г.
- ^ Гонгриджп, Джулиан. «модули/index-default.js» . underscorejs.org . Проверено 4 марта 2021 г.
Внешние ссылки
[ редактировать ]- Официальный сайт
- Функциональный Javascript Оливера Стила (интернет-архив; на сайте osteele.com сохраняется только снимок экрана )
- Микрошаблоны JavaScript от Джона Резига, первоначальный источник вдохновения для
_.template