Полифилы JavaScript: что это и зачем они нужны?

от автора

Кирилл Мыльников

Frontend разработчик в Usetech

Всем привет, я — Кирилл Мыльников, frontend разработчик компании Usetech.

Сегодня хочу рассказать о полифилах JavaScript: что это и зачем они нужны? На практике мы реализуем несколько полифилов: map, forEach, filter, reduce. 

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

Итак, начнём с определения полифила, а затем перейдём к методам.

Что такое полифил?

Полифил — это код, реализующий какую-то функциональность, которая не поддерживается в некоторых браузерах. Реализация собственного полифила обеспечивает единообразное поведение функциональности в разных браузерах.

Как я писал выше, сегодня мы будем реализовывать несколько полифилов: map, forEach, filter, reduce.

Метод map

Метод map вызывает функцию для каждого элемента и возвращает новый массив.  Аргумент функции принимает три значения:

  1. Элемент массива;

  2. Индекс данного элемента;

  3. Сам массив.

Реализуем полифил на примере:

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; }

А теперь поэтапно разберём, что тут происходит. Сначала нам нужно обработать возникающие ошибки:

  1. Функцию обратного вызова могут не передать;

  2. Данный метод вызывается не для массива.

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 нужно учесть несколько моментов:

  1. Он используется только для перебора и ничего не возвращает;

  2. Изменяет оригинальный массив.

Реализация полифила будет очень похожа на метод 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. В основном его применяют для вычисления какого-нибудь единого значения на основе всего массива. Функция применяется по очереди ко всем элементам и переносит свой результат на следующий вызов.

Аргументы функции:

  1. previousValue — результат предыдущего вызова;

  2. item — элемент массива;

  3. index — индекс данного элемента;

  4. 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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *