Редакция Highload разобралась, как и зачем использовать метод map() массива JavaScript, на реальных примерах.
Содержание:
1. Что представляет собой метод map() в JavaScript?
2. Синтаксис и параметры метода map() в JavaScript
2.1. Параметры
2.2. Возвращаемое значение
3. Примеры использования map() в JavaScript
3.1. С одним аргументом
3.2. С двумя аргументами
3.3. С тремя аргументами
4. Совместимость
5. Полифил
6. Когда не следует использовать map()
7. Дополнительные примеры
7.1. Преобразование строки в массив
7.2. Рендеринг списков с помощью React
7.3. Переформатирование массива
8. Сложности использования метода map()
Заключение
Метод map() массивов JavaScript применяет указанную функцию последовательно к каждому элементу массива и создает новый массив из результатов.
const args = [1, 2, 3, 4]; const squares = args.map(x => x * x); console.log(squares)
Приведенный выше код возводит в квадрат элементы массива args и создает из результатов новый массив squares:
[1, 4, 9, 16]
Метод map() не изменяет исходный массив и выполняет функцию только для тех элементов, которым присвоены значения (в том числе, undefined).
Метод map() — это возможность ECMAScript5 (ES5). ES5 (JavaScript 2009) полностью поддерживается всеми современными браузерами.
Для метода map() используются такие сигнатуры:
// Сигнатура со стрелкой
array.map((element) => { /* ... */ })
array.map((element, index) => { /* ... */ })
array.map((element, index, arr) => { /* ... */ })
// Функция обратного вызова
array.map(callbackFn)
array.map(callbackFn, thisValue)
// Вложенная функция обратного вызова
array.map(function(element) { /* ... */ })
array.map(function(element, index) { /* ... */ })
array.map(function(element, index, arr){ /* ... */ })
array.map(function(element, index, arr) { /* ... */ }, thisValue)
array | Исходный массив, к элементам которого будет применена функция. |
function() | Обязательный. Функция, которая будет применяться к каждому элементу массива. |
element | Обязательный. Значение текущего элемента. |
index | Необязательный. Индекс текущего элемента. |
arr | Необязательный. Массив текущего элемента. |
thisValue | Необязательный. Значение по умолчанию — Значение, которое передается функции в качестве |
Массив с результатами применения функции к каждому элементу исходного массива.
array.map((element) => { /* ... */ })
Допустим, имеется список из топ-3 игр 2021 года. Требуется вывести названия игр и разработчиков. Для этого подойдут сигнатуры с одним аргументом. Вот как это можно сделать, используя сигнатуру map() со стрелкой:
<!DOCTYPE html>
<html>
<head>
<title>
Метод map() массива JavaScript
</title>
</head>
<body>
<div id="root"></div>
<script>
var el = document.getElementById('root');
const top3_games = [
{name: "Deathloop", dev: "Arkane Studios"},
{name: "Halo Infinite", dev: "343 Industries"},
{name: "Metroid Dread", dev: "MercurySteam and Nintendo EPD"}
];
var game_list = top3_games.map(game => [game.name, game.dev].join(" by "));
el.innerHTML = JSON.stringify(game_list);
</script>
</body>
</html> В результате выполнения в элемент div с идентификатором root будет помещено следующее:
["Deathloop by Arkane Studios","Halo Infinite by 343 Industries","Metroid Dread by MercurySteam and Nintendo EPD"]
Тот же самый результат получим с использованием функции обратного вызова:
var game_list = top3_games.map(getInfo);
function getInfo(game) {
return [game.name, game.dev].join(" by ");
}
и с помощью вложенной функции:
var game_list = top3_games.map(function(game) {
return [game.name, game.dev].join(" by ");
});
Запись со стрелкой — самая компактная, в то время как в отдельной функции можно гибко разместить крупный фрагмент кода.
Теперь давайте выведем игры под порядковыми номерами. Для получения порядкового номера воспользуемся вторым аргументом функции: index.
Для простоты возьмем пример сигнатуры со стрелкой и изменим строку, в которой применяется метод map():
var game_list = top3_games.map((game, index) => `${index + 1}. ${[game.name, game.dev].join(" by ")}`);
Теперь в начале каждого значения будет указан его порядковый номер, который на единицу больше индекса:
["1. Deathloop by Arkane Studios","2. Halo Infinite by 343 Industries","3. Metroid Dread by MercurySteam and Nintendo EPD"]
В качестве третьего аргумента функции обратного вызова передается исходный массив. Мы можем использовать его, например, если нужно указать общее количество элементов:
var game_list = top3_games.map((game, index, arr) => `${index + 1} of ${arr.length}: ${[game.name, game.dev].join(" by ")}`);
В результате получим:
["1 of 3: Deathloop by Arkane Studios","2 of 3: Halo Infinite by 343 Industries","3 of 3: Metroid Dread by MercurySteam and Nintendo EPD"]
Метод map() JavaScript поддерживается современными браузерами. В приведенной ниже таблице указаны версии браузеров и платформ, начиная с которых реализована его поддержка.
| Chrome | 1 |
| Edge | 12 |
| Firefox | 1.5 |
| IE | 9 |
| Opera | 9.5 |
| Safari | 3 |
| WebView Android | 37 |
| Chrome Android | 18 |
| Firefox for Android | 4 |
| Opera Android | 10.1 |
| Safari on iOS | 1 |
| Samsung Internet | 1.0 |
| Deno | 1.0 |
| Node.js | 0.10.0 |
Что делать, если используемая версия браузера не поддерживает метод map()? В этом случае метод можно заменить полифилом. Полифил (англ. polyfill) — это фрагмент кода, реализующий новую функциональность в устаревших версиях браузеров, которые не поддерживают современные функции.
Полифил для Array.prototype.map доступен в core-js. Но его можно написать и самостоятельно. Для этого нужно реализовать функцию, в которой:
<!DOCTYPE html>
<html>
<head>
<title>
Полифил для метода map() массива JavaScript
</title>
</head>
<body>
<div id="root"></div>
<script>
var el = document.getElementById('root');
Array.prototype.pfMap = function(callbackFn) {
var result = [];
for (var i = 0; i < this.length; i++) {
result.push(callbackFn(this[i], i, this));
}
return result;
}
var doubled = [1, 2, 3, 4, 5].pfMap(x => x * 2);
el.innerHTML = JSON.stringify(doubled);
</script>
</body>
</html>
В этом примере кода на странице выводится массив с удвоенными значениями элементов исходного массива:
[2,4,6,8,10]
map() — один из методов, с помощью которых можно производить итерацию по массиву. Но существуют ситуации, когда использовать его нецелесообразно. Это случаи, когда:
В таких случаях рекомендуется пользоваться forEach и for...of.
Как уже упоминалось в разделе выше о полифилах, метод map() — это метод прототипа массива Array.prototype.map. Возможности JavaScript позволяют перенести этот метод в контекст строки и выполнить итерацию, перебрав ее по символам. Это можно сделать, вызвав map() с помощью метода call().
<!DOCTYPE html>
<html>
<head>
<title>
Преобразование строки в массив
</title>
</head>
<body>
<div id="root"></div>
<script>
var el = document.getElementById('root');
const line = "Do or do not. There is no try.";
const map = Array.prototype.map;
const newLine = map.call(line, currentChar => {
return `${currentChar}`
});
el.innerHTML = JSON.stringify(newLine);
</script>
</body>
</html>
В итоге каждый символ станет отдельным строковым элементом нового массива:
["D","o"," ","o","r"," ","d","o"," ","n","o","t","."," ","T","h","e","r","e"," ","i","s"," ","n","o"," ","t","r","y","."]
Метод map() можно использовать для рендеринга списков, например в React. Вот содержимое JSX-файла компонента, который выводит слова из массива в виде списка:
import React from "react";
import ReactDOM from "react-dom";
const words = ["каждый", "охотник", "желает", "знать", "где", "сидит", "фазан"];
const WordList = () => (
<div>
<ul>{words.map(word => <li key={word}> {word} </li>)}</ul>
</div>
);
ReactDOM.render(<WordList />, document.getElementById("root"));
Результат:
С помощью метода map() можно изменить объекты внутри массива, по которому производится итерация. В приведенном ниже коде проводится преобразование массива, в котором указаны названия топ-3 языков программирования в 2021 году и годы их создания, в массив с названиями этих языков и их местами по популярности.
<!DOCTYPE html>
<html>
<head>
<title>
Переформатирование массива JavaScript с помощью map()
</title>
</head>
<body>
<div id="root"></div>
<script>
var el = document.getElementById('root');
const top3_languages = [
{name: "Python", year: 1991},
{name: "Java", year: 1995},
{name: "JavaScript", year: 1995}
];
var language_places = top3_languages.map(function(game, index) {
var item = {};
item["place"] = index + 1;
item["name"] = game.name;
return item;
});
el.innerHTML = JSON.stringify(language_places);
</script>
</body>
</html> Код выводит следующий массив:
[{"place":1,"name":"Python"},{"place":2,"name":"Java"},{"place":3,"name":"JavaScript"}]
Методу map() можно передавать не только пользовательские, но и встроенные функции. Передавая встроенные функции, следует обращать особое внимание на количество аргументов, которые они принимают. Рассмотрим следующий пример.
<!DOCTYPE html>
<html>
<head>
<title>
map() и встроенные функции
</title>
</head>
<body>
<div id="root"></div>
<script>
document.getElementById("root").innerHTML =
["5", "4", "3", "2", "1"].map(parseInt);
</script>
</body>
</html>
На первый взгляд, этот код тривиален и должен выдать последовательность 5, 4, 3, 2, 1, преобразовав строки в целые числа. Но фактически мы получаем значения 5, NaN, NaN, 2, 1. Почему так происходит?
Метод parseInt принимает два аргумента: строку и основание системы счисления. В то же время функция обратного вызова передает три значения: элемент, индекс и массив.
Посмотрим, что происходит при выполнении этого кода. Из трех значений, передаваемых функции parseInt, последнее игнорируется. В качестве аргумента для преобразования передается 5, а в качестве основания системы счисления — 0 (индекс первого элемента). Когда parseInt принимает второе значение 0, а строка не начинается с «0x», используется десятичная система счисления. Поэтому в результате первое значение — 5.
Диапазон значений для основания системы счисления в parseInt — числа от 2 до 36. Второе значение в массиве («4») имеет индекс 1, который выходит за пределы допустимых значений второго параметра parseInt. Поэтому в результате выполнения итерации для этого значения получаем NaN.
На следующей итерации будет передано основание 2, но в двоичной системе счисления нет цифры 3, и снова получаем NaN.
Далее получаем 2 и 1, потому что в троичной и четверичной системах есть эти цифры.
Существует несколько решений этой проблемы.
Можно создать «враппер» для parseInt, который будет явно принимать один аргумент и передавать основание 10:
arr = ["5", "4", "3", "2", "1"];
function toInt(el){
return parseInt(el, 10);
}
document.getElementById("root").innerHTML = arr.map(toInt); То же решение можно переписать с использованием сигнатуры со стрелкой:
document.getElementById("root").innerHTML = arr.map(
str => parseInt(str)
);
И третьим решением будет применение Number:
document.getElementById("root").innerHTML = arr.map(Number); Метод map() массива JavaScript пригодится, когда требуется применить определенную функцию к произвольному количеству аргументов и получить результаты в новом массиве. Его целесообразно использовать, когда нужно оставить исходный массив без изменений. В противном случае рекомендуется использовать другие средства, не создающие нового массива.
Как обычно, в заключение предлагаем посмотреть подробное видео про метод массива map():
На фоне роста спроса на ликвидность в бычьем рынке 2025 года, криптозаймы снова выходят на…
Прокси (proxy), или прокси-сервер — это программа-посредник, которая обеспечивает соединение между пользователем и интернет-ресурсом. Принцип…
Согласитесь, было бы неплохо соединить в одно сайт и приложение для смартфона. Если вы еще…
Повсеместное распространение смартфонов привело к огромному спросу на мобильные игры и приложения. Миллиарды пользователей гаджетов…
В перечне популярных чат-ботов с искусственным интеллектом Google Bard (Gemini) еще не пользуется такой популярностью…
Скрипт (англ. — сценарий), — это небольшая программа, как правило, для веб-интерфейса, выполняющая определенную задачу.…