У вас в тесте используется Math.random() - очень тяжелая операция, так что большая часть времени у вас в тесте .push - время исполнения Math.random(). Если его заменить на счетчик, разница будет ещё значительней - примерно, двукратная. Почему - разбираться и копаться в сгенерированном коде лень. Может, особенности доступа к полям / модификации объектов.
"this === null || this === window условие сработает в том случае, если метод вызывается как отдельная функция" - что это?
В спецификации прописаны 2 вещи:
this приводится к объекту с помощью операции ToObject - данная операция кидает ошибку на null и undefined.
Метод должен быть задан в строгом режиме.
По идее, никто не запрещает запускать .map на window:
[].map.call(window, it => it); // => [global]
А у вас, кроме этого, полифил не будет работать в окружении, отличном от браузера, где нет window - та же NodeJS.
Если ваш метод таки задается в строгом режиме, что явно не прописано ('use strict' - но может быть и контекст модуля), проблем у вас больше. Например, примитивы не будут приводиться к объектам:
[].map.call('1', (v, i, o) => typeof o); // => ['object']
[].myMap.call('1', (v, i, o) => typeof o); // => ['string']
и далее. Обычно, полифилы данных методов, добавленных в ES5, рассчитаны на ES3 браузеры - и у них есть своя специфика.
Например, как было показано на примерах выше, данные методы - дженерики. Это значит, что они могут работать не только на массивах - но и на любых array-like сущностях - например, строках. Вот только в старых движках (IE8-, где строки не индексированы) без дополнительных костылей с этим проблемы - а где-то, например в старых версиях V8, есть соответствующие баги. И это только один момент специфики старых движков, что нужно учитывать.
Полифил должен обнаруживать уже имеющуюся нативную фичу и использовать её, если есть такая возможность. Хотя бы так,
var myMap = [].map || function map() { /* ... */ };
но обычно все куда сложнее.
Пожалуйста, не пишите полифилы ES для использования в вашем проекте сами, если на все 100 не уверены, что без этого никак - обычно, можно найти уже готовые, проверенные, где кол-во ошибок сведено к минимуму.
Данные методы были добавлены в ES5 (IE9), ES6 разве что незначительно меняет их семантику - но тут даже о корректности по ES5 говорить не приходится -)
Хмм, а какие браузеры полностью поддерживают ES6? Я ни одного не знаю. Например, оптимизация хвостовой рекурсии (вернее, PTC) поддерживается сейчас только в Safari.
Эти компоненты добавили не позже классов, а вместе с ними (а что-то, вроде возможности установки прототипа существующего объекта, было задолго до них - де факто, но не в стандарте). И это делает классы синтаксическим сахаром, смотрим хотя бы на определение из педивикии
Под «синтаксическим сахаром» понимается любой имеющийся в языке программирования синтаксический элемент, механизм, способ описания, который дублирует другой, имеющийся в языке элемент или механизм, но является более удобным в использовании, или более краток, или выглядит естественнее, или более привычен (похож на аналогичные элементы других языков), или просто лучше воспринимается при чтении программы человеком.
Справедливости ради, для ES6+ классы это исключительно синтаксический сахар. С помощью new.target (доступен и в обычных функциях), 3го аргумента Reflect.construct, Object.setPrototypeOf и WeakMap реализуются все недоступные в ES5 части логики классов.
Вы ошибаетесь чуть менее, чем во всем. Давайте рассмотрим только "итого":
__proto__ — это свойство любого объекта в JS, которое является ссылкой на свойство prototype функции-конструктора
Нет, это не свойство любого объекта в JS. Это legacy (сейчас в стандарте он опциональный - рекомендуется использовать Object.setPrototypeOf / Object.getPrototypeOf - про которые в посте и слова не сказано) accessor, расположенный на Object.prototype. Для объектов, не унаследованный от Object.prototype (например, Object.create(null)) его не будет. Оно может быть перекрыто собственным свойством объекта. Есть ещё __proto__ в литерале объекта, но это немного другое.
у каждой функции в JS есть свойство prototype, но только у функций!
Далеко не у каждой функции в JS есть свойство .prototype - оно есть только у конструкторов. Его нет у стрелочных функций, функций заданных синтаксисом методов ({ method() { /* ... */ } }), асинхронных функций, built-in функций и других.
Потомок связан с родителем свойством __proto__, которое указывает на свойство prototype родителя
Про __proto__ смотрите первый пункт. А про prototype - конструкторы не единственный способ наследования - на чей prototype будет указывать Object.create({}).__proto__?
И так глаза режет практически каждый абзац статьи.
Подождите, вы безосновательно обвинили меня в "агитации и призыву к свержению власти" - и это утверждение висело, судя по дате добавления, полторы недели - и вместо того, что бы хотя бы извиниться - поставили минус моему комментарию? -)
Не совсем понял, что данной строчкой вы хотите показать - здесь подключается плагин babel-plugin-polyfill-corejs3, на стороне которого сейчас и находится вся логика, ответственная за подключение core-js и на стороне которого разбираются опции.
Простой пример - метод Array.prototype.at был добавлен в стандарт относительно недавно. esnext версия появилась в core-js@3.8, стабильная - в core-js@3.17. Видит Babel array.at(i), таргет IE - импорт чего ему вставлять? В core-js@3.0 нет ни es.array.at, ни esnext.array.at, попытка их импорта сломает код. Поэтому и пришлось добавить такой костыль.
Да уж, во времена ES13 звучит впечатляюще.
Простой пример, попивший крови. Хотя мажорная версия на то и мажорная.
Ну пару if'ов можно сократить и до одного, вот только это сокращает время всего на пол наносекунды.
У вас в тесте используется
Math.random()- очень тяжелая операция, так что большая часть времени у вас в тесте.push- время исполненияMath.random(). Если его заменить на счетчик, разница будет ещё значительней - примерно, двукратная. Почему - разбираться и копаться в сгенерированном коде лень. Может, особенности доступа к полям / модификации объектов.Простая очередь:
Результаты:
Как-то так.
При этом, генератор по
Symbol.iteratorна каждый шаг итерации создает эти самые объекты и поля - хотя, возможно, движок это и оптимизирует.Вообще, интересно было бы посмотреть на сравнение производительности с очередью, реализованной классически, с цепочкой объектов.
Давайте разберем, что не так в ваших полифилах, на примере
.map.Эти методы должны быть объявлены как неперечесляемые свойства.
Зачем? Есть такие странные люди, что обходят массивы при помощи цикла
for-in:Подобные "полифилы" очень часто ломает чужой код. И это, пожалуй, самая популярная ошибка, при их написании.
.mapи прочие методы массива, добавленные в ES5, игнорируют дырки в массивах.Как выше упомянул @kahi4, длина массива должна запоминаться до начала итерации
Кроме того, в этот момент длина должна приводиться с помощью внутренней операции
ToLength- но это уже мелочи жизни.С ES6, для поддержки субклассинга,
.mapиспользует@@speciesпаттерн, его поддержка реализуется в несколько дополнительных строк."
this === null || this === windowусловие сработает в том случае, если метод вызывается как отдельная функция" - что это?В спецификации прописаны 2 вещи:
thisприводится к объекту с помощью операцииToObject- данная операция кидает ошибку наnullиundefined.Метод должен быть задан в строгом режиме.
По идее, никто не запрещает запускать
.mapнаwindow:А у вас, кроме этого, полифил не будет работать в окружении, отличном от браузера, где нет
window- та же NodeJS.Если ваш метод таки задается в строгом режиме, что явно не прописано (
'use strict'- но может быть и контекст модуля), проблем у вас больше. Например, примитивы не будут приводиться к объектам:и далее. Обычно, полифилы данных методов, добавленных в ES5, рассчитаны на ES3 браузеры - и у них есть своя специфика.
Например, как было показано на примерах выше, данные методы - дженерики. Это значит, что они могут работать не только на массивах - но и на любых array-like сущностях - например, строках. Вот только в старых движках (IE8-, где строки не индексированы) без дополнительных костылей с этим проблемы - а где-то, например в старых версиях V8, есть соответствующие баги. И это только один момент специфики старых движков, что нужно учитывать.
Полифил должен обнаруживать уже имеющуюся нативную фичу и использовать её, если есть такая возможность. Хотя бы так,
но обычно все куда сложнее.
Пожалуйста, не пишите полифилы ES для использования в вашем проекте сами, если на все 100 не уверены, что без этого никак - обычно, можно найти уже готовые, проверенные, где кол-во ошибок сведено к минимуму.
Данные методы были добавлены в ES5 (IE9), ES6 разве что незначительно меняет их семантику - но тут даже о корректности по ES5 говорить не приходится -)
Хмм, а какие браузеры полностью поддерживают ES6? Я ни одного не знаю. Например, оптимизация хвостовой рекурсии (вернее, PTC) поддерживается сейчас только в Safari.
Эти компоненты добавили не позже классов, а вместе с ними (а что-то, вроде возможности установки прототипа существующего объекта, было задолго до них - де факто, но не в стандарте). И это делает классы синтаксическим сахаром, смотрим хотя бы на определение из педивикии
Ну по поводу классов смотрите чуть выше.
Справедливости ради, для ES6+ классы это исключительно синтаксический сахар. С помощью
new.target(доступен и в обычных функциях), 3го аргументаReflect.construct,Object.setPrototypeOfиWeakMapреализуются все недоступные в ES5 части логики классов.Вы ошибаетесь чуть менее, чем во всем. Давайте рассмотрим только "итого":
Нет, это не свойство любого объекта в JS. Это legacy (сейчас в стандарте он опциональный - рекомендуется использовать
Object.setPrototypeOf/Object.getPrototypeOf- про которые в посте и слова не сказано) accessor, расположенный наObject.prototype. Для объектов, не унаследованный отObject.prototype(например,Object.create(null)) его не будет. Оно может быть перекрыто собственным свойством объекта. Есть ещё__proto__в литерале объекта, но это немного другое.Далеко не у каждой функции в JS есть свойство
.prototype- оно есть только у конструкторов. Его нет у стрелочных функций, функций заданных синтаксисом методов ({ method() { /* ... */ } }), асинхронных функций, built-in функций и других.Про
__proto__смотрите первый пункт. А проprototype- конструкторы не единственный способ наследования - на чейprototypeбудет указыватьObject.create({}).__proto__?И так глаза режет практически каждый абзац статьи.
Удачной отладки -) И для этого есть свои причины, только одна из них.
Полифилы по usage у swc совсем не production-ready, что и не скрывают. Оптимизация по entry, с недавнего времени, работает вполне неплохо.
Подождите, вы безосновательно обвинили меня в "агитации и призыву к свержению власти" - и это утверждение висело, судя по дате добавления, полторы недели - и вместо того, что бы хотя бы извиниться - поставили минус моему комментарию? -)
Зашел посмотреть на их список - и внезапно обнаружил... себя.
Очевидно, что
toxic-reposне проверяет данные хоть как-то.Неплохо. Несколько дополнений:
Не рассмотрены такие относительно свежие вещи, как:
Про
awaitверхнего уровня небольшая ошибка - с недавних пор его можно использовать в контексте модуля.Можно было бы расширить вещами, всё ещё не добавленными в стандарт языка, но активно применяемые сообществом, вроде
Observable.Прошел месяц - ни исправления, ни ответа...
@babel/compat-dataсобирается из compat-table.Не совсем понял, что данной строчкой вы хотите показать - здесь подключается плагин
babel-plugin-polyfill-corejs3, на стороне которого сейчас и находится вся логика, ответственная за подключениеcore-jsи на стороне которого разбираются опции.Простой пример - метод
Array.prototype.atбыл добавлен в стандарт относительно недавно.esnextверсия появилась вcore-js@3.8, стабильная - вcore-js@3.17. Видит Babelarray.at(i), таргет IE - импорт чего ему вставлять? Вcore-js@3.0нет ниes.array.at, ниesnext.array.at, попытка их импорта сломает код. Поэтому и пришлось добавить такой костыль.Вообще, смотрим документацию.