|
Collection v5
Всем здрасти!:)
Закончил работу над Collection 5. Для тех, кто не в курсе, то что такое Collection. И так, что нового: 1) Поддержка всех новых видов коллекций и технологий, а именно: Map, Set, WeakMap, WeakSet, генераторов, итераторов на основе протокола @@iterator. var foo = new Map([[{}, 1], [null, 2]]); $C(foo).map(el => el * 2) // new Map([[{}, 2], [null, 4]]) function *i() { for (let i = 0; i < 10; i++) { yield i; } } $C(i).get(el => el > 5) // [6, 7, 8, 9] Работает во всех последних версиях браузеров (включая ИЕ). 2) Новый пласт методов и свойств для работы в контексте конкретного итератора. $C([1, 2, 3, 4]).forEach(function (el) { if (el == 2) { this.break(); } }); $C([1, 2, 3, 4]).get(function (el) { if (el == 2) { this.modi(1); } return true; }); // [1, 2, 4] Подробнее в доке. 3) Новый метод filter (частный случай map), in, новые режимы для метода extend. 4) 100% code review который в итоге вылился в значительное улучшение интерфейсов методов (собственно поэтому версия 5, а не 4.3). Основные изменения по сравнению с 4-й версией: 4.1) Метод remove возвращает массив или объект удалённых элементов; 4.2) Метод set возвращает массив или объект обновлённых элементов; 4.3) Метод add возвращает объект статуса добавления; 4.4) Параметр методов useForIn был заменён на более универсальный use с опциями работы: 'for', 'for in', 'for of'. 4.5) Метод groupKeys был удалён в пользу простого group с параметров saveKeys. В остальном улучшения интерфейсов не нарушили обратную совместимость. 5) Более 900 новых тестов, а также заменён qUnit на Jasmine 2. 6) Улучшен модуль генерации кода, что дало в некоторых случаях дополнительный прирост производительности. 7) Оптимизация методов search и remove с помощью нового АПИ контекста итераторов позволило увеличить скорость работы в 2 раза. 8) Расширен механизм указателей для работы с новыми видами коллекций. 9) Исправлено множество ошибок, улучшены комментарии, теперь Collection на 100% проходит строгую проверку Closure Lint. 10) Проведена дополнительная оптимизация кода для работы в WebStorm (в результате которого было отправлено более 20-ти багов для JetBrains :) ) - теперь работает почти идеальный автокомплит и в WebStorm последней версии включены множество исправлений :) 11) Значительно улучшена документация и перенесена в Wiki. Собственно, что пишу сейчас: кому не лень, почитайте имеющиеся доку на Wiki и скажите замечания и т.д. т.к. доку для меня писать самое сложное :) |
Круто)
Цитата:
|
а как ты реализуешь итератор для браузеров, которые поддерживают Map и Set, но не поддерживают @@iterator?
|
Цитата:
PS: Наглядный пример использования протокола @@iterator в работе: // Для более сахарного вида используем итератор на основе генератора $C(function *() { var str = '1-2 4-5 6-7'; var rgxp = /(\d+)-(\d+)/g; var tmp; while ((tmp = rgxp.exec(str))) { yield tmp; } }).get() // [["1-2", "1", "2"], ["4-5", "4", "5"], ["6-7", "6", "7"]] // Можно любому объекту или классу определить свойство @@iterator и Collection это поймёт $C({'@@iterator': function *() { for (let i = 0; i < 10; i++) { yield i; } }}).get() // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] |
kobezzza, ты в полифили Map юзаешь let, на сколько я помню он поддерживается только лисой , как тогда работает в других браузерах ?
|
Цитата:
Сама либа работает в ИЕ6+, но кстати let и const работают уже во всех последних версиях браузеров. PS: Пример написания фильтра который отбирает только уникальные / не уникальные значения на основе нового АПИ контекста forEach. $C().addFilter('unique', function (el, key, data, i, length) { if (!this.$.init) { let cache = this.$.cache = this.$.cache || new Set(); let final = this.$.final = this.$.final || new Set(); if (cache.has(el)) { final.delete(el); } else { final.add(el); cache.add(el); } if (i === (this._.endIndex || (length() - 1))) { this.jump(0); this.$.init = true; } return this.FALSE; } return this.$.final.has(el); }); $C([1, 2, 3, 2, 3, 9]).get('unique') // [1, 9] $C([1, 2, 3, 2, 3, 9]).get('!unique') // [2, 3, 2, 3] |
Юху! Я сделал это :) Collection 5 доведён до релиза :dance:
PS: Как же приятно доводить дело до конца :) Сейчас смотрю: *) 9.5+к строк кода *) 1000+ тестов *) Вики по 100% функционалу :) PSPS: Таки решил выделить день на написание статьи на Хабр, надеюсь завтра к вечеру закончу. |
Цитата:
|
Цитата:
Ну а вообще чтобы иметь единый и мощный интерфейс для всех видов коллекций и чтобы работало так же быстро как на простых циклах. |
Цитата:
|
Цитата:
Да и максимальная сборка либы - это всего 16 килобайт, объём такой же как и у underscore, а функционал несоизмеримо больше, а про скорость я вообще молчу. В общем на JavaScript.ru как обычно: "описание не читал, но по любому не нужон" :) |
Цитата:
|
Цитата:
Эта либа общего назначения, т.е. использовать её можно везде, все мои проекты (кроме Snakeskin, т.к. только в 5-й версии был добавлен механизм "контекста forEach") используют Collection. Одно "но", чтобы писать на Collection нужно любить функциональщину, т.е. не шарахаться от map / reduce и прочего, т.к. либа явно декларирует именно такой подход. Пример, функция которая преобразовывает dash-style в camelCase String.prototype.convertDashStyleToCamelCase = function () { return $C(this).reduce(function (res, el) { if (el !== '-') { res += this.$.up ? el.toUpperCase() : el; } this.$.up = el === '-'; return res; }, ''); }; Обратная операция String.prototype.convertCamelCaseToDashStyle = function () { return $C(this).reduce(function (res, el) { var lc = el.toLowerCase(); return res + (el !== lc ? '-' : '') + lc; }, ''); }; Отбор элементов для пагинации $C(...).forEach(function (el) { ... }, {startIndex: 10, count: 10}); Тоже самое, но в обратном порядке $C(...).forEach(function (el) { ... }, {startIndex: 10, count: 10, reverse: true}); Количество вхождений каждого символа в строке $C('fooobar1212').group(el => el) Количество вхождений буквы 'o' в строке $C('fooobar1212').length(el => el == 'o') Преобразовать объект {ключ: значение} в Set из значений, которые больше 1 $C({a: 1, b: 2, c: 3}).map(el => el, {initial: new Set, filter: el => el > 1}) При этом не важно, что мы итерируем, хоть массив, объект, Map, Set, генератор, строку и т.д. все методы работают одинаково и со скоростью циклов, но в сахарном функциональном виде. Примеров можно сделать уйму, но достаточно взглянуть на методы: https://github.com/kobezzza/Collection/wiki |
Написал короткую описательную статейку на хабр
|
Цитата:
|
Цитата:
т.е. пишем на обычном LS завёрнутую конструкцию, а это дело разворачивается в один вызов $C без всяких "var $C = require("Collection")" |
Цитата:
Цитата:
var collection = require("collection.js"); global.$C = collection.$C; global.Collection = collection.Collection; И всё, можно нигде больше не кидать require :) PS: следует заметить, что я не против require, просто в случае с Collection его нужно подключать везде и это утомляет :) |
Цитата:
хотя... спад производительности почти незаметен в LS... а если нужны производительные части, можно вызвать $C ) Цитата:
|
Цитата:
Я то хотел сделать единое навороченное функциональное АПИ для всех видов итерируемых данных :) |
Выпустил микроапдейт: 5.0.1.
|
Цитата:
|
Цитата:
|
Цитата:
Вообще мечтаю когда будет: import std; std::math.round(...); std::number.parse_int(...); А не эта шляпа: Math.round parseInt |
parseInt ➝ Number.parseInt
|
Цитата:
|
Цитата:
Цитата:
Цитата:
|
жесть в том, что
Number.parseInt === parseInt ➝ true но Number.isNaN === isNaN ➝ false и поведение у isNaN разное |
Octane, ну какбэ логично: старый isNaN будет deprecated, но останется для совместимости. Новые скрипты надо будет писать сразу по новому.
На счёт оправданности нового поведения ничего сказать не могу.) |
Написал ещё одну коротенькую статью: http://habrahabr.ru/post/225995/
|
В ноде мне часто нужны extend, extend_deep, clone, clone_deep, все остальное как мне кажется лишнее...., т.к. for/of поддерживает даже итератор протокол.
Может сделать микро-либу только для ноды? :) |
Цитата:
Цитата:
|
Цитата:
Цитата:
|
Цитата:
|
Цитата:
break, continue, @@iterator, yield, есть, условные выражения, что еще нужно? Вижу только один минус — hasOwnProperty вроде не проверяет и @@iterator для строк хотят убрать А вообще мне нода очень сильно не нравится..... полдня искал нормальный вотчер для файлов, около двадцати проектов выкинул в поймоку, т.к. они либо не работают, либо работают криво, в итоге остановился на chokidar |
Цитата:
// Вернуть массив элементов исходной коллекции, которые $C(new Map(...)).get({ reverse: true, // В обратном порядке startIndex: 10, // Начиная с 10-го итерационного индекса from: 5, // Пропустить 5 успешных итераций count: 10 // Не более 10 успешных итераций (не считая from), filter: 'unique && !odd' // Только уникальные не чётные элементы }) Напиши это на for of и ужаснись. А вообще давай не будем спорить, можешь не отвечать. |
Цитата:
Я просто хочу услышать от тебя, насколько часто ты сам используешь такие алгоритмические "цепочки" и на каких задачах ты понял что нужен Collection? |
Цитата:
Данный пример выдран из контекста, где идёт реализация пагинации. Цитата:
|
Цитата:
Цитата:
|
Выпустил апдейт v5.0.2.
Главное нововведение: это новая сборка collection.light, которая включает в себя только набор основных итераторов и весит ~9кб (т.е. почти в 2 раза меньше полной сборки). |
Выпустил апдейт 5.0.3. Теперь для обхода объекта, если не задан флаг notOwn и доступен нативный Object.keys применяется стратегия: keys + for, что дало заметный прирост производительности.
|
Часовой пояс GMT +3, время: 11:19. |
|