полифил js что это
Polyfill (полифил) в JavaScript — это код, написанный на JavaScript, который позволяет использовать новые функции языка, даже если они не поддерживаются старыми или устаревшими браузерами.
Например, если новая версия JavaScript включает новый метод массива, но старый браузер не поддерживает этот метод, вы можете написать полифил, который добавит этот метод в объект массива. Таким образом, вы можете использовать новый метод во всех браузерах, включая старые.
Полифилы — это часто используемый инструмент в веб-разработке, потому что они позволяют использовать новые функции языка, не отказываясь от поддержки старых браузеров.
Полифилы JavaScript: что это и зачем они нужны?

Всем привет, я — Кирилл Мыльников, 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(`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 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(`$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(`$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(`$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. Если он не указан, то мы инициализируем первый элемент массива, и начинаем обход со второго элемента.
Мы разобрали несколько примеров реализации полифилов, а также возникающие ошибки и методы их исправления. Спасибо за то, что уделили время прочтению статьи. А в комментариях можете поделиться своим опытом создания и реализации полифилов.
- Блог компании Usetech
- JavaScript
Полифиллы — JS: DOM API
DOM непрерывно развивается. Какие-то браузеры его адаптируют быстрее, какие-то медленнее. Все это не позволяет легко и непринужденно пользоваться последними новинками. Разработчикам каждый раз нужно думать, какие браузеры распространены у пользователей их проектов.
Как выяснить, какие браузеры актуальны? Обычно об этом узнают из аналитики. Например, можно использовать Google Analytics, которая в режиме реального времени собирает данные обо всех, кто заходит на сайт.
В особо сложных ситуациях приходится поддерживать совсем старые браузеры, которые практически ничего не могут. Такое нередко встречается в государственных организациях.
Например, есть метод matches() , который ищет элементы по CSS-селекторам. Он поддерживается Internet Explorer, но только с девятой версии. Если в вашем проекте заявлена совместимость с восьмой версией, то на вызов этого метода мы получим ошибку:
const div = document.querySelector('div'); div.matches('.someClass'); // Uncaught TypeError: matches is not a function
К счастью, JavaScript позволяет частично компенсировать недостатки старых браузеров. Благодаря прототипам разработчики могут добавить недостающую функциональность прямо в реализацию DOM. Делается это с помощью полифиллов, которые мы изучим сегодня.
Общий принцип работы этих библиотек следующий:
- Проверяем наличие нужного метода или свойства
- Если их нет, то добавляем
Важно, чтобы библиотека с полифиллами грузилась до выполнения любого другого кода. Только в этом случае остальной код может рассчитывать на то, что все нужные свойства будут в наличии.
Добавление метода
Рассмотрим пример полифилла для метода node.matches() . Он работает для всех популярных браузеров и задействует их специфику, что видно по именам свойств:
(function(constructor) const p = constructor.prototype; if (!p.matches) p.matches = p.matchesSelector || p.mozMatchesSelector || p.msMatchesSelector || p.oMatchesSelector || p.webkitMatchesSelector; >; >)(window.Element);
После выполнения этого кода мы можем использовать метод element.matches() , не боясь, что его не будет в старых браузерах.
Добавление свойства
Более сложный вариант – добавление свойства ParentNode.lastElementChild . Здесь приходится программировать логику поиска нужного элемента:
// Обратите внимание, что добавление свойства производится особым образом, // из-за которого свойство становится динамическим и ленивым // Другими словами, его значение будет вычисляться только в момент обращения if (!('lastElementChild' in document.documentElement)) Object.defineProperty(Element.prototype, 'lastElementChild', get: function() for (let nodes = this.children, n, i = nodes.length — 1; i >= 0; --i) if (n = nodes[i], 1 === n.nodeType) return n; > > return null; > >); >
Примеры выше не совсем полные. Если бы мы посмотрели исходники соответствующих библиотек, мы бы удивились, как много кода в них. Все таки обеспечение универсальной работы во всех браузерах и всех версиях — это непростая задача.
Чтобы проверить поддержку определенных фич в разных браузерах, можно воспользоваться ресурсом Can I use :
А самый простой способ добавить полифиллы на сайт — это воспользоваться проектом polyfill.io .
Кроме этого проекта, на GitHub есть много готовых полифиллов для любых частей DOM. Они разбросаны по разным репозиториям разных людей. Поэтому если вам понадобится что-то полифиллить, то сначала придется поискать нужную библиотеку.
Иногда нам нужно просто проверить наличие определенной фичи и выполнить разный код в зависимости от результата. В такой ситуации поможет библиотека modernizr:
// Проверяется наличие flash Modernizr.on('flash', (result) => if (result) // the browser has flash > else // the browser does not have flash > >);
Ядро JavaScript
Полифиллы бывают не только для DOM. Сам JavaScript тоже непрерывно развивается.
Многие фичи современного JavaScript настолько упростили разработку, что без них уже сложно. Поэтому практически ни один современный проект не обходится без библиотеки core-js . Она закрывает почти все возможности современного JavaScript.
Чтобы использовать эту библиотеку, нужно установить ее как зависимость проекта и подключить ее на самом верхнем уровне приложения. И все — дальше она делает всю работу сама, поэтому нам не приходится собирать приложения через webpack:
import 'core-js/stable'; // Другие зависимости
Открыть доступ
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
- 130 курсов, 2000+ часов теории
- 1000 практических заданий в браузере
- 360 000 студентов
Наши выпускники работают в компаниях:
Использование полифиллов при написании кросс-браузерных приложений
Недавно со мной случилась одна весёлая история. Я сделал веб-проект и расширил возможности уже существующего приложения, которым в моей организации пользуются кадровики. Всё выглядело просто отлично, я радовался тому, что проект был запущен, с нетерпением ожидая благодарственных писем.
Через несколько дней после первого релиза я, и правда, начал получать письма. Но благодарностей в них не наблюдалось. Мне писали менеджеры, работники кадровой службы, и все те, кто пытался воспользоваться моей программой. Все они говорили, что у них приложение работает неправильно.

В чём же дело? А дело в том, что я, создавая проект, тестировал его в Chrome. Но пользователи этого проекта постоянно применяют Firefox и IE. Работа с моим приложением не стала исключением. Мне, в итоге, было совсем невесело от того, что проект, запущенный пару дней назад, надо было дорабатывать.
Собственно говоря, тут мне на помощь и пришли полифиллы.
Полифиллы
Полифилл (polyfill или polyfiller) — это фрагмент кода (или некий плагин), реализующий то, наличия чего разработчик ожидает среди стандартных возможностей браузера. Полифиллы позволяют, так сказать, «сгладить» неровности браузерных API.
В веб-среде полифиллы обычно представлены JavaScript-кодом. Этот код используется для оснащения устаревших браузеров современными возможностями, которые эти браузеры не поддерживают.
Например, с помощью полифилла можно сымитировать функционал HTML-элемента Canvas в Microsoft Internet Explorer 7. Для этого применяется плагин Silverlight. Средствами полифилла может быть реализована поддержка единиц измерения rem в CSS, или атрибута text-shadow, или чего угодно другого. Причины, по которым разработчики не пользуются исключительно полифиллами, не обращая внимание на встроенные возможности браузеров, заключаются в том, что стандартные возможности браузеров обеспечивают более качественный функционал и более высокую производительность. Собственные браузерные реализации различных API обладают более широкими возможностями, чем полифиллы, да и работают быстрее.
Иногда полифиллы используются для решения проблем, связанных с тем, что различные браузеры по-разному реализуют одни и те же возможности. Подобные полифиллы взаимодействуют с некоторыми браузерами, используя их нестандартные особенности, и дают другим JavaScript-программам доступ к определённым механизмам, соответствующий стандартам. Надо отметить, что подобные причины использования полифиллов сегодня уже не так актуальны, как раньше. Особую распространённость полифиллы имели во времена IE6, Netscape и NNav, когда каждый браузер реализовывал возможности JavaScript не так, как другие.
Пример
Недавно я опубликовал руководство по разработке приложения, конвертирующего CSV и Excel-файлы в JSON с помощью JavaScript. Здесь можно посмотреть на готовое приложение.
Для того чтобы разобраться с тем, о чём мы будем говорить дальше, вы можете либо сделать всё то, о чём идёт речь в руководстве, либо клонировать мой репозиторий следующей командой:
git clone https://github.com/YannMjl/jsdemo-read-cvs-xls-json cd jsdemo-read-cvs-xls-json
Рекомендую в процессе работы пользоваться VS Code. Запустить веб-приложение можно локально, с использованием расширения для VS Code Live Server.
Давайте модифицируем это веб-приложение и посмотрим на проблемы, которые возникают при работе с ним с использованием разных браузеров.
Создадим в репозитории ветку polyfill и переключимся на неё:
git checkout -b polyfill
Я собираюсь исследовать ситуацию, в которой мы получаем данные из двух или большего количества CSV-файлов, и, после завершения обработки результатов запросов к соответствующим API, выводим эти данные в HTML-таблицу.
▍Доработка проекта
Создадим в корневой директории проекта новый CSV-файл ( team2.csv ), в результате чего там должно оказаться два файла. Вот файл, который я добавил в проект.
Модифицируем файл script.js так, чтобы он читал бы данные из 2 файлов и выводил бы все данные в HTML-таблицу. Вот мой script.js :
Теперь, скопировав адрес страницы, откройте проект во всех браузерах, которые у вас есть. В моём случае это были Internet Explorer, Firefox Mozilla, Microsoft Edge и Google Chrome. Оказалось, что приложение перестало нормально работать в Internet Explorer и Microsoft Edge. Там выводились только заголовки.

Страница проекта в Chrome

Страница проекта в Microsoft Edge
У того, что на странице, выводимой некоторыми браузерами, нет данных, две причины:
- Я пользовался промисами и коллбэками, которые поддерживают не все браузеры. Например, среди таких браузеров — IE и Edge.
- Я пользовался методом массивов flat() для того, чтобы создать из существующего массива новый «плоский» массив. Этот метод не поддерживается некоторыми браузерами. Среди них, как и в предыдущем случае, IE и Edge.
▍Применение полифиллов
Исправим проблему промисов и коллбэков, воспользовавшись библиотекой Bluebird. Это — полномасштабная JS-реализация механизмов, связанных с промисами. Самая интересная особенность библиотеки Bluebird заключается в том, что она позволяет «промисифицировать» другие Node-модули, обрабатывая их так, чтобы с ними можно было бы работать асинхронно. Такую обработку можно применить к коду, в котором используются коллбэки.
Загрузим библиотеку Bluebird на страницу, воспользовавшись соответствующим CDN-ресурсом. Для этого разместим в заголовке файла index.html (в элементе head ) следующее:
Для того чтобы исправить проблему, касающуюся метода массивов flat() , добавим в верхнюю часть файла script.js следующий код:
Object.defineProperty(Array.prototype, 'flat', < value: function (depth) < depth = 1; return this.reduce( function (flat, toFlatten) < return flat.concat((Array.isArray(toFlatten) && (depth >1)) ? toFlatten.flat(depth - 1) : toFlatten); >, [] ); >, configurable: true >);
Теперь приложение должно работать во всех браузерах так, как ожидается. Вот, например, как оно теперь выглядит в Microsoft Edge.

Страница доработанного проекта в Microsoft Edge
Я развернул этот проект здесь. Можете его испытать.
Если у вас не получилось добиться работоспособности проекта — загляните в мой репозиторий.
А вот — для примера — ещё пара полифиллов.
// полифилл для String.prototype.startsWith() if (!String.prototype.startsWith) < Object.defineProperty(String.prototype, 'startsWith', < value: function (search, rawPos) < pos = rawPos >0 ? rawPos | 0 : 0; return this.substring(pos, pos + search.length) === search; > >); > // полифилл для String.prototype.includes() if (!String.prototype.includes) < String.prototype.includes = function (search, start) < 'use strict'; if (typeof start !== 'number') < start = 0; >if (start + search.length > this.length) < return false; >else < return this.indexOf(search, start) !== -1; >>; >
Итоги
Полифиллы были особенно актуальны раньше, но и в наши дни они способны помочь в разработке кросс-браузерных веб-проектов. Надеемся, что приведённый здесь пример позволил тем, кто раньше не знал о полифиллах, по-новому взглянуть на проблему создания сайтов, рассчитанных на различные браузеры.
Уважаемые читатели! Пользуетесь ли вы полифиллами?