Кирилл Мыльников
Frontend разработчик в Usetech
Всем привет, я — Кирилл Мыльников, frontend разработчик компании Usetech.
Сегодня хочу рассказать о полифилах JavaScript: что это и зачем они нужны? На практике мы реализуем несколько полифилов: map, forEach, filter, reduce.
Эта статья подойдёт новичкам, которые готовятся к собеседованию, и опытным специалистам. В комментариях вы можете рассказать о том, как реализуете полифилы в своей работе.
Итак, начнём с определения полифила, а затем перейдём к методам.
Что такое полифил?
Полифил — это код, реализующий какую-то функциональность, которая не поддерживается в некоторых браузерах. Реализация собственного полифила обеспечивает единообразное поведение функциональности в разных браузерах.
Как я писал выше, сегодня мы будем реализовывать несколько полифилов: map, forEach, filter, reduce.
Метод map
Метод map вызывает функцию для каждого элемента и возвращает новый массив. Аргумент функции принимает три значения:
-
Элемент массива;
-
Индекс данного элемента;
-
Сам массив.
Реализуем полифил на примере:
Array.prototype.myMap = function (callback, arg) { if (this == null || this === window) { throw TypeError('myMap called on null or undefined') } if (typeof callback !== 'function') { throw TypeError(`{callback} is not a function`) } const newArray = []; for (let i = 0; i < this.length; i++) { newArray[i] = callback.call(arg, this[i], i, this) } return newArray; }
А теперь поэтапно разберём, что тут происходит. Сначала нам нужно обработать возникающие ошибки:
-
Функцию обратного вызова могут не передать;
-
Данный метод вызывается не для массива.
this === null || this === window, условие сработает в том случае, если метод вызывается как отдельная функция.
Пример:
const myMap = Array.prototype.myMap;
myMap();
Внутри функции myMap this уже будет как global, не в строгом режиме будет window, в строгом undefined. Для этого кейса мы выкидываем ошибку.
Также функцию обратного вызова могут не передать, и на этот случай мы делаем проверку на typeof callback === ‘function’
Наша функция принимает второй аргумент arg. Для чего это нужно? Если наша функция обратного вызова должна быть вызвана в контексте, для внутреннего callback должно быть установлено значение arg. Это можно сделать с помощью call().
Вот таким простым способом мы с вами реализовали полифил метода map. Теперь перейдём к следующему методу.
Метод forEach
При реализации следующего полифила метода forEach нужно учесть несколько моментов:
-
Он используется только для перебора и ничего не возвращает;
-
Изменяет оригинальный массив.
Реализация полифила будет очень похожа на метод map. Посмотрим на примере:
Array.prototype.myForEach = function (callback, arg) { if (this == null || this === window) throw TypeError('myForEach called on null or undefined'); if (typeof callback !== 'function') throw TypeError(`${callback} is not a function`); for (let i = 0; i < this.length; i++) { callback.call(arg, this[i], i, this); } };
Проверки остались такими же, как и реализация, только мы ничего не возвращаем, а просто перебираем.
Метод filter
Этот метод возвращает новый массив всех подходящих элементов. Посмотрим пример:
Array.prototype.myfilter = function (callback, arg) { if (this == null || this === window) throw TypeError('myfilter called on null or undefined'); if (typeof callback !== 'function') throw TypeError(`${callback} is not a function`); const newArr = []; for (let i = 0; i < this.length; i++) { if (callback.call(arg, this[i], i, this)) newArr.push(this[i]); } return newArr; };
Как вы видите, в этом случае присутствует обработка ошибок, как и у всех.
Единственное, что поменялось, это то, что мы написали проверку, удовлетворяющую условию, перед тем как добавить в массив и вернуть его.
Перейдём к последнему методу — reduce.
Метод reduce
Прежде чем приступить к разбору на практике, нужно вспомнить, как работает метод reduce. В основном его применяют для вычисления какого-нибудь единого значения на основе всего массива. Функция применяется по очереди ко всем элементам и переносит свой результат на следующий вызов.
Аргументы функции:
-
previousValue — результат предыдущего вызова;
-
item — элемент массива;
-
index — индекс данного элемента;
-
array — сам массив.
Теперь перейдём к реализации полифила reduce:
Array.prototype.myReduce = function (callback, initValue) { if (this === null || this === window) throw TypeError('myReduce called on null or undefined'); if (typeof callback !== 'function') throw TypeError(`${callback} is not a function`); let previousValue = initValue; let startIndex = 0; if (initValue === null) { previousValue = this[0]; startIndex = 1; } if (previousValue == null) throw TypeError('Reduce of empty array with no initial value'); for (let index = startIndex; index < this.length; index++) { previousValue = callback(previousValue, this[index], index, this); } return previousValue; };
Первые две проверки я уже описывал выше. Но появилась новая проверка: если previousValue будет undefined, если массив пуст и не указан initialValue, то тоже выдаём ошибку.
Второй аргумент reduce initialValue необязательный, и он используется для инициализации previousValue. Если он не указан, то мы инициализируем первый элемент массива, и начинаем обход со второго элемента.
Мы разобрали несколько примеров реализации полифилов, а также возникающие ошибки и методы их исправления. Спасибо за то, что уделили время прочтению статьи. А в комментариях можете поделиться своим опытом создания и реализации полифилов.
ссылка на оригинал статьи https://habr.com/ru/company/usetech/blog/687288/
Добавить комментарий