lodash (underscore) — знай свою стандартную библиотеку

    image

    Знающие люди рекомендуют разработчикам периодически пробегать глазами свою стандартную библиотеку, чтобы лучше представлять ее возможности. Зачем очередной раз изобретать велосипед, когда до нас уже столько сделано, и, главное, хорошо оттестировано, а бывает даже и нормально задокументировано. Говорят, полное использование стандартной библиотеки здорово повышает производительность.

    Что же, в последнее время, в своей работе я во всех проектах задействую lodash (кому-то может больше нравиться underscore). Для меня это, фактически, — стандарт. В очередной раз пробегая глазами API, я решил составить для себя шпаргалку в виде: «название функции» — «краткое описание». Так удобно освежать API в памяти. Может кому пригодится.

    Массивы

    compact
    Убираем из массива все пустые элементы (0, "", null, undefined)
    difference
    Создаем новый массив, как разницу, где из первого массива исключили все значения второго (А-Б)
    findIndex
    Возвращает индекс первого элемента, по которому callback вернул true
    findLastIndex
    Возвращает индекс первого с конца элемента, по которому callback вернул true
    first
    Возвращает первый или несколько первых элементов массива
    flatten
    Извлекает, в виде массива, элементы из объектов, содержащихся в передаваемом массиве
    indexOf
    Возвращает индекс первого совпадающего (===) элемента, если массив сортирован можно ускорить поиск
    initial
    Возвращает начальную часть массива (кроме n последних)
    intersection
    Возвращает пересечение массивов (нескольких)
    last
    Возвращает последний или несколько последних элементов массива
    lastIndexOf
    Возвращает индекс последнего совпадающего (===) элемента. (можно искать не с самого конца)
    pull
    Удаляет переданные элементы из массива
    range
    Создает массив с числами от start до end (можно выбрать шаг)
    remove
    Удаляет из массива элементы по заданному правилу и возвращает массив удаленных элементов
    rest
    Возвращает все кроме первого (нескольких первых) элементов массива
    sortedIndex
    Возвращает индекс вставки текущего значения в сортированном массиве
    union
    Возвращает массив уникальных значений — результат объединения нескольких массивов
    uniq
    Создает копию массива без дубликатов
    without
    Создает новый массив из существующего исключая некоторые значения
    xor
    Создает новый массив — «семантическую разницу» между переданными массивами
    zip
    Создает массив сгруппированных в подмассивы элементов. На вход принимает несколько массивов. Собирает так: первые элементы всех входных массивов попадают в первую группу и т.д.
    zipObject
    Собирает объект из двух массивов (с ключами и со значениями)

    Коллекции

    at
    Создает новую коллекцию, только из перечисленных элементов
    contains
    Проверяет, содержится (содержатся) ли определенный элемент в коллекции
    countBy
    Создает объект, ключами которого будут значения, возвращаемые функцией обратного вызова, а значениями — количество соответствующих возвратов
    every
    Проверка на то, что все элементы коллекции истины (или удовлетворяют условию).
    filter
    Пробегает по всем элементам коллекции и возвращает МАССИВ из элементов, удовлетворяющих условию
    find
    Возвращает первый элемент коллекции, отвечающий заданным критериям
    findLast
    То же самое, что и find, только с конца
    forEach
    Пробегается по всем элементам коллекции, запуская функцию обратного вызова для каждого элемента
    forEachRight
    То же самое, что и forEach, только с конца
    groupBy
    Создает коллекцию, ключами которой являются значения, возвращенные функцией обратного вызова, а значениями — массивы из первоначальных элементов коллекции
    indexBy
    Создает коллекцию, ключами которой являются значения, возвращенные функцией обратного вызова, а значениями — последние элементы первоначальной коллекции с соответствующим ключом
    invoke
    Выполняет определенный метод для каждого элемента коллекции и возвращает массив из результатов этого выполнения
    map
    Создает массив элементов, прогоняя каждый элемент коллекции через функцию обратного вызова
    max
    Возвращает максимальное значение коллекции
    min
    Возвращает минимальное значение коллекции
    pluck
    Возвращает все значения определенного свойства коллекции
    reduce
    Уменьшаем коллекцию до значения, получаемое вызовом функций обратного вызова для каждого значения. В эту функцию, кроме самого значения, передается также результат предыдущего вызова.
    reduceRight
    То же самое, что и reduce, только с конца
    reject
    В противоположность filter — эта функция возвращает массив элементов коллекции, которые не удовлетворяют условию
    sample
    Возвращает случайный элемент коллекции
    shuffle
    Возвращает массив из перемешанных в случайном порядке элементов коллекции
    size
    Возвращает размер коллекции
    some
    Проверка на то, что хотя бы один элемент коллекции истинен (или удовлетворяет условию).
    sortBy
    Возвращает массив сортированных по возрастанию элементов коллекции. Для сортировки используются значения получаемые функцией обратного вызова по каждому элементу.
    toArray
    Преобразует коллекцию к массиву. Полезно для работы с arguments
    where
    Проводит глубокое сравнение каждого элемента с определенным объектом. Возвращает массив, удовлетворяющий сравнению.

    Функции

    after
    Возвращает функцию, которая вызовет переданный колбек только после n-ого вызова
    bind
    Возвращает функцию, которая при вызове будет привязана к текущему this, к привязанным аргументам и аргументам, предающимся в саму вызванную функцию.
    bindAll
    Привязывает все методы объекта к самому этому объекту (this в методах всегда будет сам объект)
    bindKey
    Привязывает метод объекта к самому объетку (на момент привязки, метод может еще не существовать)
    compose
    Возвращает функцию — композицию из переданных функций. Передаем f,g,h — возвращает функцию = f(g(h()))
    curry
    Принимает на вход функцию с n параметрами, а возвращает функцию, которая в случае если параметро достаточно — вызовет входную, если нет, возвратит другую функцию, передав оставшиеся параметры которой — вызовется первоначальная.
    debounce
    Возвращает функцию, которая запустит входную функцию только выдержав паузу после своего последнего запуска. (устранение дребезжания)
    defer
    Вызовет входную функцию тогда, когда освободится текущий стек вызова (в начале следующего цикла событий)
    delay
    Вызовет входную функцию через n миллисекунд
    memoize
    Возвращает функцию, которая кэширует результаты своего выполнения, и не выполняется, если результат есть в кэше.
    once
    Возвратит функцию, которая вызовет входную только один раз. В последующие разы будет возвращаться полученный результат.
    partial
    То же самое, что и bind, но не привязывает this
    partialRight
    То же самое, что и partial, но привязывается к параметрам справа
    throttle
    Возвращает функцию, которая вызывает исходную не чаще чем один раз в n миллисекунд
    wrap
    Создает функцию, в первый параметр которой будет передан первый параметр врапера.

    Объекты

    assign
    Дополняет объект отсутствующими (не просто undefined) свойствами из другого объекта
    clone
    Делает копию объекта (вложенные объекты копируются по ссылке)
    cloneDeep
    Глубокое копирование объекта (вложенные объекты копируются по содержанию)
    create
    Создает объект по переданному прототипу и свойствам
    defaults
    Дополняет объект отсутствующими (=== undefined) свойствами из другого объекта — задает умолчания
    findKey
    Ищет первый объект удовлетворяющий условиям — возвращает ключ
    findLastKey
    Ищет последний объект удовлетворяющий условиям — возвращает ключ
    forIn
    Обходит все свойства объекта (включая внутренние), вызывая для каждого из них функцию обратного вызова
    forInRight
    То же самое что и forIn только с конца
    forOwn
    Обходит все собственные свойства объекта, вызывая для каждого из них функцию обратного вызова
    forOwnRight
    То же самое что и forOwn только с конца
    functions
    Возвращает отсортированный массив имен всех свойств объекта, значениями которых ялвяются функции
    has
    Проверяет, является ли указанное свойство собственным свойством объекта
    invert
    Создает объект у которого ключи и значения поменяны местами
    isArguments
    Проверяет, является ли значение — объектом arguments
    isArray
    Проверяет, является ли значение массивом
    isBoolean
    Проверяет, является ли значение булевой переменной
    isDate
    Проверяет, является ли значение массивом
    isElement
    Проверяет, является ли значение DOM-элементом
    isEmpty
    Проверяет, является ли значение пустым. Массивы, строки, arguments-объекты с нулевой длинной считаются пустыми
    isEqual
    Проводит глубокое сравнение двух значений
    isFinite
    Проверяет, является ли данное значение конечным числом, или же оно может быть приобразовано к нему
    isFunction
    Проверяет, ялвяется ли данное значение функцией
    isNaN
    Проверяет значение на === NaN (это не то же самое, что стандартная isNuN, которая возвращает true для undefined и не числовых значений)
    isNull
    Проверяет значение на === null
    isNumber
    Проверяет, является ли значение числом (NaN тоже считается числом)
    isObject
    Проверяет, является ли значение объектом
    isPlainObject
    Проверяет, является ли значение чистым объектом (созданным конструктором Object)
    isRegExp
    Проверяет, является ли значение регулярным выражение
    isString
    Проверяет, является ли значение строкой
    isUndefined
    Проверяет значение на === undefined
    keys
    Возвращает массив ключей объекта
    mapValues
    Созает новый объект с такими же ключами, как у исходного, значения получаются вызовом callback-функции к каждому элементу
    merge
    Рекурсивно добавляет переданные объекты в объект назначения
    omit
    Возвращает объект, у которого убраны некоторые свойства
    pairs
    Создает из объекта двумерный массив, типа [[key1, value1], [key2, value2]].
    pick
    Создает из объекта другой объект со свойствами из списка
    transform
    Более простая альтернатива reduce — позволяет трансформировать входящий объект в другой, посредством функции обратного вызова, в которую передается кроме элементов еще и результирующий объект
    values
    Возвращает массив значений объекта

    Утилиты

    now
    Возвращает текущий Unix-time в миллисекундах
    constant
    Создает функцию, возвращающую переданное значение
    createCallback
    Создает функцию, коллбек — используется для внутренних целей lodash
    escape
    Экранирует символы &, <, >, ", и ' соответсующими html-сущностями
    identity
    Функция возвращает первый переданный в нее аргумент
    mixin
    Добавляет в объект (или в сам lodash) элементы преданного объекта. Если объект-приемник — функция, добавляет свойства в прототип.
    noConflict
    Делает _ равным старому значению (до запуска lodash), и возвращает указатель на lodash
    noop
    Пустая функция. Возвращает undefined
    parseInt
    Извлекает число из строки, по умолчанию работает всегда с 10-ой системой счисления (в отличии от стандартной)
    property
    Возвращает функцию в стиле pluck, вызов которой с объектом в качестве параметра, вернет значение определенного свойства.
    random
    Вернет случайное число из диапазона. Может дробное.
    result
    Вернет значение свойства в объекте (если значением будет функция, она будет вызвана и возвращен ее результат)
    runInContext
    Вернет новую lodash-функцию привязанную к заданному контексту
    template
    Микрошаблонизатор
    times
    Выполняет указанный callback n-раз, возвращая массив результатов
    unescape
    Функция, обратная escape
    uniqueId
    Возвращает уникальный числовой ID (число, каждый раз на единицу больше. можно передавать префикс)

    P.S. Я сам, конечно, не использовал все 100% функций в своей работе, поэтому возможны неточности — пишите в личку, все поправлю. По поводу орфографии — туда же.
    Метки:
    Поделиться публикацией
    Комментарии 62
    • 0
      gj
      • +7
        Все ссылки поломаны (пробел после #).
        • +2
          Как по мне, так это не шпаргалка, а краткий, обрезанный перевод документации.
          Шпаргалка вот так примерно выглядит: Javascript cheat sheet
          • 0
            Перевод документации кто-то уже делает в сети lodash.ru, но как-то вяло.
          • +4
            Предпочитаю SugarJS. Он проигрывает Lo-Dash в производительности, но значительно удобнее и естественнее в использовании.

            sugarjs.com/

            Для тех же, кому производительность критична, рекомендую LazyJS. В случаях, когда после объода свойств объекта/массива не требуется вернуть новый объект со всеми свойствами, LazyJS выигрывает у Lo-Dash в производительности. На составных операциях разрыв становится значительным. Например, на операции map -> filter LazyJS в пять раз быстрее, чем Lo-Dash, и в пятнадцать, чем SugarJS. Если же вам нужно не просто пройтись по значениям свойств, а собрать новый объект/массив, то LazyJS теряет преимущество.

            danieltao.com/lazy.js/

            Бенчмарки десяти аналогичных библиотек: danieltao.com/lazy.js/comparisons.html

            Извините, не могу нормально оформить ссылки. Наказан фанатами Half-Life за непопулярное мнение.
            • +4
              Добавлю. что производительность, на мой взгляд, имеет значение только на обработке сколько-нибудь больших объемов данных. Если вы работаете с фронтендом, то никакой разницы в быстродействии этих библиотек вы не обнаружите.
              • +1
                а что, расширять прототипы встроенных объектов уже разрешили?
                • 0
                  Конечно: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

                  Возможно, мнение, будто это невозможно, происходит из факта того, что это невозможно в IE8 и ниже.
                  • 0
                    Я не имел в виду что невозможно, я имел в виду что нельзя. Это глобальная область видимости. Будут конфликты рано или поздно.
                    • +1
                      Да, в Ruby, например, для решения этой проблемы придумали Refinements. Перед тем, как использовать свои или чужие модификации глобальных объектов в своем коде, ты можешь указать, какие из модификаций тебе нужны. В JS такого нет и, скорее всего, никогда не будет.

                      Однако большой проблемы я в этом не вижу. Да, нужно проявлять некоторую осторожность. Если в команде несколько программистов и каждый будет расширять глобальные объекты десятками методов для решения сиюминутных задач, то возможен конфликт.

                      Решение простое: так делать не нужно. Расширяйте глобальные объекты только для того, чтобы за стандартную библиотеку JS не было стыдно. Не меняйте работу стандартных методов. Документируйте, какие свойства вы (пере)определяете. Используйте юнит-тестирование.
                      • 0
                        При любой осторожности проблемы будут, может меньше и реже, но будут. Зачем использовать подход который пораждает проблемы и требует дополнительной осторожности? В javascript и без того нужна большая осторожность, особенно для новичков.

                        И ради чего? Всего-то чтобы кое-где на пару символов меньше кода написать.
                        • 0
                          Приводите примеры этих ужасных проблем, или ваше утверждение голословно. Суеверие какое-то.

                          В том-то и дело, что JS — это динамический язык, он позволяет такие вещи, и они работают прекрасно.
                          • 0
                            есть две библиотеки типа sugarjs мне нужны обе, я не могу подключить их обе, например
                            • 0
                              И что? Это проблема другого рода. Вы ее спрогнозировали заранее при планировании проекта и можете решить ее любым способом, который вам нравится. Эта проблема не приведет к непредсказуемым результатам, о которых тут все говорят, а примера привести не могут.

                              Я пока не столкнулся с сиутацией, чтобы нужная мне функция отсутствовала в Sugar, но была доступна в Lo-Dash. Но если такое произойдет, то я прежде всего попытаюсь добавить ее в SugarJS. Разработчик у SugarJS очень отзывчивый.
                              • 0
                                > Я пока не столкнулся с сиутацией, чтобы нужная мне функция отсутствовала в Sugar

                                Эта функция может быть нужна не мне, а третьей библиотеке, которая нужна мне. Или могут быть две библиотеки типа SugarJS, но совсем про разное и будут обе нужны непосредственно мне.

                                > Эта проблема не приведет к непредсказуемым результатам, о которых тут все говорят, а примера привести не могут.

                                Сами придумайте. Тут ничего особенного, просто кто-то переопределит чей-то метод. Это всеравно что все методы underscore вынести из _ в window. Ну будут же конфликты, согласитесь.

                                Или вы предлагаете принцип что только одна библиотека может расширять прототипы? Но кто решает кому можно, а кому нельзя?

                                Повторюсь, может проблемы не такие уж и серьезные, и может их можно избегать путем договоренностей (внутри команды, между майнтейнерами библиотек и т.д.) Но зачем всё это нужно если можно просто не трогать прототипы?
                                • +1
                                  Не надо использовать опциональные зависимости вроде SugarJS или Lo-Dash в библиотеках.

                                  При написании библиотек нужно стремиться к тому, чтобы исключить использование вспомогательных библиотек. Все, что делают Lo-Dash и SugarJS, можно сделать и вручную — с той же или большей производительностью.

                                  Если бы эта рекомендация повсеместно нарушалась, то при установке зависимостей вашего проекта вы бы получали кашу из Underscore, Lo-Dash, Prototype, MooTools, Signals, Zepto…

                                  И лично SugarJS тут совершенно ни при чем.
                                  • 0
                                    > При написании библиотек нужно стремиться к тому, чтобы исключить использование вспомогательных библиотек.

                                    Я хочу иметь возможность использовать любые библиотеки, в том числе и плохо написанные и с зависимостями. Обычно я не буду конечно устраивать кашу из Underscore, Lo-Dash, Prototype, MooTools, Signals, Zepto…, но хочется иметь возможность это сделать при необходимости.

                                    И вы не на весь комментарий ответили.
                              • –1
                                Вот пример, как расширяют протоип нативного объекта в крупной библиотеке: github.com/douglascrockford/JSON-js/blob/master/json2.js#L174

                                Обратите внимание, что это делает не кто-нибудь, а Дуглас Крокфорд — апологет JS и, в числе прочего, автор JSLint.
                                • +2
                                  Это полифил. Полифилы — единственное допустимое место где можно так делать.
                      • 0
                        Так ведь это и нужно в IE8 и ниже. Остальные уже поддерживают ES5.
                        • 0
                          Кстати, а при чем тут defineProperty и ие8? Чтобы расширить прототип встроенного объекта defineProperty не нужен.
                          • –2
                            Если просто сделать `Object.prototype foo = function () {}`, то новое свойство будет enumerable. Это сломает работу всего на свете.

                            defineProperty позволяет создавать не-enumerable свойства, безопасные во всех отношениях.
                            • +1
                              > безопасные во всех отношениях.
                              а что по повоу «Это глобальная область видимости. Будут конфликты рано или поздно.»?
                      • 0
                        ИМХО — у него еще пара минусов.
                        Одно дело — добавление в прототип своих методов, реализация полифилов, соответствующих спецификации, но подмена нативных методов собственными…

                        ['one','two','three'].map('length'); // => [3,3,5]
                        

                        Объектное api отсутствует как таковое. Как и undescore / lodash, больно избыточен. Многие методы практически дублируют другие.
                        • 0
                          Подмена нативных методов собственными в случае SugarJS сделана аккуратно и не нарушает работу существующего кода. Там не меняется поведение переопределенных методов, а только добавляются новые возможности. Эти возможности не будут задействованы, если вы будете пользоваться переопределенными методами как обычно.
                        • +1
                          github.com/lodash/lodash/issues/274 ленивые вычисления на цепочках планируются в LoDash версии 3.
                          • 0
                            Сделал скромную ставку в $15 на этот тикет. Приглашаю присоединиться к спонсированию: freedomsponsors.org/core/issue/497/
                            • 0
                              О, так это вы. Увидел на гитхабе раньше, чем здесь.
                        • –3
                          Вот что мне не нравиться в undescore — это то что они не стали выносить методы в прототипы нативных объектов js. То есть выносить .map() в прототип Array я считаю намного правильней ибо это приучает тебя писать в стили нового стандарта ECMAScript 5 (уже конечно не такого нового) и дает вам возможность скажем на мобильных устройствах не использовать библиоткеу да и вообще приучает к использованию нового апи. под _.method я бы выносил только те функции которые не попали в спецификацию
                          • +3
                            Поддерживаю. По этой причине предпочитаю SugarJS (см. коммендарий выше).

                            > _.method я бы выносил только те функции которые не попали в спецификацию

                            Зачем? По-моему, это просто глупо, когда апологеты JS разводят понты про протоипную модель, а когда доходит до дела, то боятся модифицировать прототип.
                            • –1
                              Вы наверное путаете что-то? В прототип таких вещей как Object.prototype Array.prototype нельзя выносить кастомные методы, я лишь предложил туда выносить методы из спецификации если таковые не поддерживаются данными праузером, причем эти методы должны работать 100% по спецификации, чтобы вызвав .map() я не получил потом бредогого созания от автора.

                              Если вы сделали собственнвй метод для работы с массивом типо quickSort() не надо его пихать в прототим массива, это будет вносить путаницу Создайте свой класс или объект с утилитными методами.

                              По-моему, это просто глупо, когда апологеты JS разводят понты про протоипную модель,


                              Вы помоему плохо их читали, идите матчасть учить, они вам говорят что методы должны быть в прототипе для реализации правильного наследования, но они вам не говорят что надо засирать стандартные классы своми методами.
                              • +4
                                совпадения по именам функций это совсем не повод так делать. вносить расширения в прототипы — задача специализированных полифилов, которые обязаны до мелочей следовать стандартам.

                                поведение отдельных функций в библиотеке может в каких-то деталях отличаться от одноименных методов стандартных объектов (не со зла, конечно, а для общего блага — ленивость, расширенный интерфейс, и т.п.).и покуда библиотека не лезет в прототипы, это вполне допустимо.
                                • 0
                                  А по-моему, это нормально.
                                  • +1
                                    > В прототип таких вещей как Object.prototype Array.prototype нельзя выносить кастомные методы
                                    > идите матчасть учить

                                    А сами подучить не хотите?

                                    obj = {};
                                    Object.prototype.foo = 1;
                                    console.log(obj.foo); // => 1
                                    • 0
                                      dbanet как и другие имел в виду, что это плохо, непредсказуемо в дальнейшем и прочее-прочее, а не то, что это невозможно сделать. Речь идет о расширении прототипов Hosted и Native objects. После того как prototype.js намудрил с расширением прототипов эти споры всегда будут актуальны.
                                      • 0
                                        > «это плохо, непредсказуемо в дальнейшем и прочее-прочее»

                                        Бремя доказательства лежит на стороне обвинения.

                                        Без аргументации ваше утверждение совершенно голословно. Суеверие какое-то.
                                        • 0
                                          Аргументация простая — сейчас прототип расширяет одна библиотека, завтра приходит хитрый джуниор, который тоже решает добавить в Array.prototype.map нужную ему функциональность, которая ломает поведение js. Или подключается другая библиотека, которая опять же хочет вмешаться в поведение js-объектов и пр. Научитесь воспринимать доводы людей, а не кричать о том, какие все тупые.
                                          • 0
                                            Если у вас в проекте участвует несколько человек, то вы должны вести по нему документацию. Документируйте, чем вы расширяете стандартную библиотеку, вот и все. Прежде, чем расширять прототипы нативных объектов (непосредственно или при помощи подключения библиотек), сверяйтесь с вашей документацией. Это же элементарный здравый смысл.

                                            Я вам тоже могу привести примеры, как можно подключением библиотек сломаь проект, безо всякого расширения прототипов. И что, это повод объявить эти библиотеки вне закона? Или может просто нужно включать голову?

                                            А с тем, что джуниор может сломать поведение JS в вашем проекте, я не спорю. Только SugarJS тут ни при чем. Он не позиционируется как защита от идиотов.
                                            • 0
                                              Речь уже далеко не про SugarJS, а про то что не надо расширять нативные объекты нестанждартной реализацией или методами, которые работают не по стандарту.
                                              И отмазка иди читать доку — не работает!
                                              Если я буду читать доку потмоу что вы изменили стандартный метод .map в прототипе массива то я буду тупо читать доки а не писать код. И даже опытный сеньер жс кодер будет вам писать 100500 ошибок, спотыкаясь на таких вещах.

                                              Наверное стандарты для того и существуют чтобы их соблюдать и упрощать жизнь?
                                  • –1
                                    Расширение прототипов, конечно, удобно, но допустимо далеко не всегда. Если вы пишите, например, модуль для Node.js, то расширять прототипы глобальных конструкторов явно не стоит.
                                    • 0
                                      > Если вы пишите, например, модуль для Node.js, то расширять прототипы глобальных конструкторов явно не стоит.

                                      Тот же SugarJS, который очень активно расширяет протоипы глобальных объектов, доступен в качестве модуля для Node. Пример использования: stackoverflow.com/a/9321954/901944 Работает это замечательно и совершенно предсказуемо.
                                      • 0
                                        Я это прекрасно знаю и использовал, в своё время. Предположим, вы пишите модуль для Node.js используя Shugar.js, заливаете его в npm. Пользователь решает его использовать в своём проекте, ставит, получает в нагрузку Sugar.js. Вот только в качестве стандартной библиотеки он использует MooTools. И проект ложится. Одно дело — писать, используя Shugar.js, конечный продукт, другое — публичный модуль.
                                        • +1
                                          Объясните, пожалуйста, почему SugarJS ломает MooTools. Я попробовал погуглить, не нашел ни подтведждений, ни опровержений.

                                          С тем, что библиотеки должны быть как можно меньше нагружены зависимостями, я совершенно согласен Например, на фронтенде я активно использую jQuery UI Widget Factory. Но когда я выношу какой-то функционал в публичный jQuery-плагин, то переписываю функционал на чистом jQuery, чтобы избавиться от лишних зависимостей.

                                          Это просто здравый смысл — не использовать опциональные зависимости в публичных библиотеках.
                                          • –1
                                            Нашел в исходниках SugarJS юнит-тесты взаимодействия с MooTools:
                                            github.com/andrewplummer/Sugar/tree/master/test/environments/mootools

                                            Так что пока вы не продемонстрируете обратное, считаю ваше утверждение голословным. Прошу демонстрировать сразу в виде баг репорта в одну из этих библиотек.
                                            • +1
                                              Вы это серьезно? Может потому, как расширяют глобальные конструкторы и их прототипы методами с одними и теми же именами, но разной сигнатурой? :) Мне приходилось разгребать после такого проекты, это страшно.

                                              // Sugar.js
                                              Object.merge(target , source, deep = false, resolve = true)
                                              // MooTools
                                              Object.merge(obj1, obj2[, obj3[, ...]])
                                              

                                              Именно по этой причине в моей стандартной библиотеке есть возможность сборки как с расширением глобальных конструкторов и их прототипов, в стиле Sugar.js, так и без, в стиле undescore.
                                              • +1
                                                Вас не смущает то что в юнит-тесты одной библиотеки пришлось добавить тест на совместимость с другой совершенно перпендикулярной библиотекой? Хорошо что их только две таких смелых, современных, а то пришлось бы побольше тестов написать :)
                                                • –3
                                                  Нет, не смущает. Вам же не приходит в голову использовать в одном проекте, например, jQuery и MooTools. Так зачем использовать вместе MooTools и SugarJS? Если у вас уже есть MooTools, используйте MooTools. И ведите документацию.
                                                  • +2
                                                    Еще раз. Объясняю на пальцах. Есть пара npm модулей, написанных не вами. Один использует MooTools, другой Shugar. Оба они добавляют метод Object.merge. В одном этот метод пытаются использовать для слияния 3 объектов, в другом — для глубокого копирования свойств. Вам в голову не приходило использовать MooTools и Shugar в одном проекте, вы даже не знаете об их существовании. Вы подключили оба эти модуля. Будет ли работать ваше приложение?
                                                    Shugar.js штука хорошая, но не панацея. Его стоит использовать только для написания конечных приложений. Undescore тоже штука хорошая, но не на столько удобна. И не дай бог мне наткнуться на npm модуль, написанный вами.
                                                    • –2
                                                      Я уже писал выше, что библиотеки должны стремиться к исключению опциональных зависимостей. В противном случае проекты будут представлять кашу из зависимостей.

                                                      SugarJS не делает ничего, что нельзя было бы выполнить нативно.

                                                      Посмотрел на npmjs.org. От MooTools зависят 16 библиотек, из них половина — расширения для MooTools.

                                                      У SugarJS ситуация хуже, от него зависят 110 библиотек. Не знаю, о чем они думают. Вероятно, описанная вами проблема до сих пор не всплывала.
                                                      • 0
                                                        Кстати, совсем забыл. Если не попросить его явно, Sugar добавляет в Object только одно новое свойство — Object.prototype.extended, которое возвращает объект, расширенный остальными фичами Sugar.

                                                        Соответственно, в вашем примере {}.merge будет выполнен MooTools, а {}.extended.merge — SugarJS.
                                                        • 0
                                                          Sugar.js в прототип Object не добавляет вообще ничего. Object.merge — статический метод конструктора в обоих библиотеках. И MooTools — только пример.
                                                          • 0
                                                            Пардон, я имел в виду это: Object.extended({foo: 'foo'}).merge({bar: 'bar'}) // => {foo: 'foo', bar: 'bar'}

                                                            Это работает, если подключить одновременно SugarJS и MooTools в любом порядке.

                                                            Ломается ли при этом MooTools, я не проверял. Как я сказал выше, SugarJS, MooTools и подобные библиотеке не должны использоваться в качестве зависимостей других библиотек. Что же касается прямых зависимостей конечного проекта, тут вы барин и можете сами решить, какую из библиотек использовать.
                                                            • 0
                                                              Последний абзац я и пытался до вас донести с самого начала.
                                                              • 0
                                                                Да, вы правы. Прошу прощения, запутался немножко в комментариях: спорю параллельно в нескольких тредах.
                                        • +1
                                          они не стали выносить методы в прототипы нативных объектов js

                                          для этого у них есть chain:

                                          var characters = [
                                            { 'name': 'barney',  'age': 36 },
                                            { 'name': 'fred',    'age': 40 },
                                            { 'name': 'pebbles', 'age': 1 }
                                          ];
                                          
                                          var youngest = _(characters)
                                              .sortBy('age')
                                              .map(function(chr) { return chr.name + ' is ' + chr.age; })
                                              .first()
                                              .value();
                                          
                                        • +2
                                          Я думаю, вам следует изменить метку «tutorial» на «перевод». А вообще, есть ведь зеркало оф. сайта на русском языке, или я не улавливаю смысла статьи?
                                          • 0
                                            Там только 3 функции переведены. А смысл в том, чтобы быстренько глазами пробежаться. Напомнив себе API.
                                            • 0
                                              Может, тогда стоит оформить эту статью как pull request к указаному выше сайту, дабы позволить людям проще находить данную информацию?
                                          • 0
                                            Статья, ради статьи, на хабре щас более 50% так
                                            P.S. хотел как ответ на вышестоящий коментарий, сорри
                                            • –1
                                              в документации почему-то про это не пишут — функции _.max() и _.min(), что в underscore, что в lodash понимают только числа, а не вообще. т.е. их нельзя использовать, например, чтобы найти в коллекции максимальную строку — получается ерунда. все потому, что. авторы underscore пытаются изобразить конкретно Math.min, и Math.max, а авторы lodash изображают underscore.
                                              • 0
                                                А, собственно, что Вам мешает использовать кастомный фильтр, который преобразует «максимальную строку» в число?
                                                • 0
                                                  имеем:
                                                  >>> 'ab' > 'aa';
                                                  true
                                                  
                                                  >>> _.max('aa', 'ab');
                                                  -Infinity
                                                  
                                                  из документации не очевидно, почему именно такой результат. тем не менее, разработчики underscore считают это поведение правильным.

                                                  в трекере мне предложили вот такой вариант для нахождения максимальной строки:
                                                  >>>  _.reduce(['aa', 'ab'], function(a, b){ return a > b ? a : b; });
                                                  'ab'
                                                  

                                                  А, собственно, что Вы предлагаете, пока не понятно.

                                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.