Сводка
Метод map()
создаёт новый массив с результатом вызова указанной функции для каждого элемента массива.
Синтаксис
arr.map(callback[, thisArg])
Параметры
callback
- Функция, создающая элемент в новом массиве, принимает три аргумента:
currentValue
- Текущий обрабатываемый элемент массива.
index
- Индекс текущего обрабатываемого элемента в массиве.
array
- Массив, по которому осуществляется проход.
thisArg
- Необязательный параметр. Значение, используемое в качестве
this
при вызове функцииcallback
.
Описание
Метод map
вызывает переданную функцию callback
один раз для каждого элемента, в порядке их появления и конструирует новый массив из результатов её вызова. Функция callback
вызывается только для индексов массива, имеющих присвоенные значения, включая undefined
. Она не вызывается для пропущенных элементов массива (то есть для индексов, которые никогда не были заданы, которые были удалены или которым никогда не было присвоено значение.
Функция callback
вызывается с тремя аргументами: значением элемента, индексом элемента и массивом, по которому осуществляется проход.
Если в метод map
был передан параметр thisArg
, при вызове callback
он будет использоваться в качестве значения this
. В противном случае в качестве значения this
будет использоваться значение undefined
. В конечном итоге, значение this
, наблюдаемое из функции callback
, определяется согласно обычным правилам определения this
, видимого из функции.
Метод map
не изменяет массив, для которого он был вызван (хотя функция callback
может это делать).
Диапазон элементов, обрабатываемых методом map
, устанавливается до первого вызова функции callback
. Элементы, добавленные в массив после начала выполнения метода map
, не будут посещены функцией callback
. Если существующие элементы массива изменяются функцией callback
, их значения, переданные в функцию, будут значениями на тот момент времени, когда метод map
посетит их; удалённые элементы посещены не будут.
Примеры
Пример: отображение массива чисел на массив квадратных корней
Следующий код берёт массив чисел и создаёт новый массив, содержащий квадратные корни чисел из первого массива.
var numbers = [1, 4, 9]; var roots = numbers.map(Math.sqrt); // теперь roots равен [1, 2, 3], а numbers всё ещё равен [1, 4, 9]
Пример: отображение массива чисел с использованием функции, содержащей аргумент
Следующий код показывает, как работает отображение, когда функция требует один аргумент. Аргумент будет автоматически присваиваться каждому элементу массива, когда map
проходит по оригинальному массиву.
var numbers = [1, 4, 9]; var doubles = numbers.map(function(num) { return num * 2; }); // теперь doubles равен [2, 8, 18], а numbers всё ещё равен [1, 4, 9]
Пример: обобщённое использование map
Этот пример показывает, как использовать map
на объекте строки String
для получения массива байт в кодировке ASCII, представляющего значения символов:
var map = Array.prototype.map; var a = map.call('Hello World', function(x) { return x.charCodeAt(0); }); // теперь a равен [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]
Пример: обобщённое использование map
вместе с querySelectorAll
Этот пример показывает, как пройтись по коллекции объектов, собранных с помощью querySelectorAll
. В данном случае мы получаем все выбранные опции на экране и печатаем их в консоль:
var elems = document.querySelectorAll('select option:checked'); var values = [].map.call(elems, function(obj) { return obj.value; });
Пример: использование map
для переворачивания строки
var str = '12345'; [].map.call(str, function(x) { return x; }).reverse().join(''); // Вывод: '54321' // Бонус: используйте '===' для проверки того, является ли строка палиндромом
Пример: хитрый вариант использования
(навеяно этой записью в блоге)
Распространённой практикой является использование функции обратного вызова с одним аргументом (элемент, над которым производится операция). Некоторые функции также широко используется с одним аргументом, хотя они принимают дополнительные необязательные аргументы. Эти привычки могут привести к неожиданному поведению программы.
// Рассмотрим пример: ['1', '2', '3'].map(parseInt); // Хотя ожидаемый результат вызова равен [1, 2, 3], // в действительности получаем [1, NaN, NaN] // Функция parseInt часто используется с одним аргументом, но она принимает два. // Первый аргумент является выражением, а второй - основанием системы счисления. // В функцию callback Array.prototype.map передаёт 3 аргумента: // элемент, его индекс и сам массив. // Третий аргумент игнорируется parseInt, но не второй, следовательно, // возможна путаница. Смотрите запись в блоге для дополнительной информации. function returnInt(element) { return parseInt(element, 10); } ['1', '2', '3'].map(returnInt); // Результатом является массив чисел (как и ожидалось) // Простейший способ добиться вышеозначенного поведения и избежать чувства "чё за!?": ['1', '2', '3'].map(Number); // [1, 2, 3]
Полифилл
Метод map
был добавлен к стандарту ECMA-262 в 5-м издании; поэтому он может отсутствовать в других реализациях стандарта. Вы можете работать с ним, добавив следующий код в начало ваших скриптов, он позволяет использовать map
в реализациях, которые не поддерживают этот метод. Этот алгоритм является точно тем, что описан в ECMA-262 5-го издания; он предполагает, что Object
, TypeError
и Array
имеют свои первоначальные значения и что callback.call
вычисляется в оригинальное значение Function.prototype.call
.
// Шаги алгоритма ECMA-262, 5-е издание, 15.4.4.19 // Ссылка (en): https://es5.github.com/#x15.4.4.19 // Ссылка (ru): https://es5.javascript.ru/x15.4.html#x15.4.4.19 if (!Array.prototype.map) { Array.prototype.map = function(callback, thisArg) { var T, A, k; if (this == null) { throw new TypeError(' this is null or not defined'); } // 1. Положим O равным результату вызова ToObject с передачей ему // значения |this| в качестве аргумента. var O = Object(this); // 2. Положим lenValue равным результату вызова внутреннего метода Get // объекта O с аргументом "length". // 3. Положим len равным ToUint32(lenValue). var len = O.length >>> 0; // 4. Если вызов IsCallable(callback) равен false, выкидываем исключение TypeError. // Смотрите (en): https://es5.github.com/#x9.11 // Смотрите (ru): https://es5.javascript.ru/x9.html#x9.11 if (typeof callback !== 'function') { throw new TypeError(callback + ' is not a function'); } // 5. Если thisArg присутствует, положим T равным thisArg; иначе положим T равным undefined. if (arguments.length > 1) { T = thisArg; } // 6. Положим A равным новому масиву, как если бы он был создан выражением new Array(len), // где Array является стандартным встроенным конструктором с этим именем, // а len является значением len. A = new Array(len); // 7. Положим k равным 0 k = 0; // 8. Пока k < len, будем повторять while (k < len) { var kValue, mappedValue; // a. Положим Pk равным ToString(k). // Это неявное преобразование для левостороннего операнда в операторе in // b. Положим kPresent равным результату вызова внутреннего метода HasProperty // объекта O с аргументом Pk. // Этот шаг может быть объединён с шагом c // c. Если kPresent равен true, то if (k in O) { // i. Положим kValue равным результату вызова внутреннего метода Get // объекта O с аргументом Pk. kValue = O[k]; // ii. Положим mappedValue равным результату вызова внутреннего метода Call // функции callback со значением T в качестве значения this и списком // аргументов, содержащим kValue, k и O. mappedValue = callback.call(T, kValue, k, O); // iii. Вызовем внутренний метод DefineOwnProperty объекта A с аргументами // Pk, Описатель Свойства // { Value: mappedValue, // Writable: true, // Enumerable: true, // Configurable: true } // и false. // В браузерах, поддерживающих Object.defineProperty, используем следующий код: // Object.defineProperty(A, k, { // value: mappedValue, // writable: true, // enumerable: true, // configurable: true // }); // Для лучшей поддержки браузерами, используем следующий код: A[k] = mappedValue; } // d. Увеличим k на 1. k++; } // 9. Вернём A. return A; }; }
Спецификации
Спецификация | Статус | Комментарии |
---|---|---|
ECMAScript 5.1 (ECMA-262) Определение 'Array.prototype.map' в этой спецификации. |
Стандарт | Изначальное определение. Реализована в JavaScript 1.6. |
ECMAScript 2015 (6th Edition, ECMA-262) Определение 'Array.prototype.map' в этой спецификации. |
Стандарт |
Совместимость с браузерами
Возможность | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|
Базовая поддержка | (Да) | 1.5 (1.8) | 9 | (Да) | (Да) |
Возможность | Android | Chrome для Android | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile |
---|---|---|---|---|---|---|
Базовая поддержка | (Да) | (Да) | 1.0 (1.8) | (Да) | (Да) | (Да) |