Единственное отличие, которое я вижу в map и foreach, состоит в том, что map
возвращает массив, а forEach
- нет. Однако я даже не понимаю последнюю строку метода forEach
"func.call(scope, this[i], i, this);
". Например, "this
" и "scope
" не ссылаются на один и тот же объект и не this[i]
и i
не ссылаются на текущее значение в цикле?
Я заметил, что в другом посте кто-то сказал: «Используйте forEach
, если вы хотите что-то сделать на основе каждого элемента списка. Например, вы можете добавлять что-то на страницу. По сути, это здорово, когда вы хотите «побочные эффекты». Я не знаю, что подразумевается под побочными эффектами.
Array.prototype.map = function(fnc) {
var a = new Array(this.length);
for (var i = 0; i < this.length; i++) {
a[i] = fnc(this[i]);
}
return a;
}
Array.prototype.forEach = function(func, scope) {
scope = scope || this;
for (var i = 0, l = this.length; i < l; i++) {
func.call(scope, this[i], i, this);
}
}
Наконец, есть ли реальное использование этих методов в javascript (поскольку мы не обновляем базу данных), кроме как для манипулирования числами следующим образом:
alert([1,2,3,4].map(function(x){ return x + 1})); //this is the only example I ever see of map in javascript.
Спасибо за любой ответ.
8 ответов
Существенное различие между map
и forEach
в вашем примере состоит в том, что forEach
работает с исходными элементами массива, тогда как map
явно возвращает новый массив в результате.
С forEach
вы предпринимаете некоторые действия с - и, возможно, изменяете - каждый элемент в исходном массиве. Метод forEach
запускает функцию, которую вы предоставляете для каждого элемента, но ничего не возвращает (undefined
). С другой стороны, map
проходит по массиву, применяет функцию к каждому элементу и выдает результат в виде нового массива .
«Побочным эффектом» forEach
является то, что исходный массив изменяется. «Отсутствие побочного эффекта» с map
означает, что при идиоматическом использовании исходные элементы массива не изменены; новый массив - это взаимно-однозначное сопоставление каждого элемента в исходном массиве - преобразование сопоставления является вашей предоставленной функцией.
Тот факт, что база данных не задействована, не означает, что вам не придется оперировать структурами данных, что, в конце концов, является одной из сущностей программирования на любом языке. Что касается вашего последнего вопроса, ваш массив может содержать не только числа, но и объекты, строки, функции и т. Д.
Я снова чувствую себя некромантом, добавляющим ответ на вопрос, который был задан 5 лет назад (к счастью, довольно недавняя активность, поэтому я не единственный, кто беспокоит мертвых :).
Другие уже написали о вашем главном вопросе о разнице между функциями. Но для...
Существуют ли реальные применения этих методов в javascript (поскольку мы не обновляем базу данных), кроме как для манипулирования числами следующим образом:
... это смешно, вы должны спросить. Только сегодня я написал фрагмент кода, который присваивает несколько значений из регулярного выражения нескольким переменным, используя map для преобразования. Он использовался для преобразования очень сложной текстовой структуры в визуализируемые данные ... но для простоты я приведу пример, использующий строки дат, потому что они, вероятно, более знакомы для всех (хотя, если бы моя проблема была на самом деле с датами вместо карты я использовал бы объект Date, который бы отлично справился с этой задачей).
const DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\.(\d{3})Z$/;
const TEST_STRING = '2016-01-04T03:20:00.000Z';
var [
iYear,
iMonth,
iDay,
iHour,
iMinute,
iSecond,
iMillisecond
] = DATE_REGEXP
// We take our regular expression and...
.exec(TEST_STRING)
// ...execute it against our string (resulting in an array of matches)...
.slice(1)
// ...drop the 0th element from those (which is the "full string match")...
.map(value => parseInt(value, 10));
// ...and map the rest of the values to integers...
// ...which we now have as individual variables at our perusal
console.debug('RESULT =>', iYear, iMonth, iDay, iHour, iMinute, iSecond, iMillisecond);
Итак ... хотя это был всего лишь пример - и только сделал очень простое преобразование для данных (просто для примера) ... сделать это без карты было бы гораздо более утомительной задачей.
Конечно, в версии JavaScript написано, что я не думаю, что слишком много браузеров поддерживают пока (по крайней мере, полностью), но - мы добираемся. Если бы мне нужно было запустить его в браузере, я думаю, что все прошло бы хорошо.
Основное различие между этими двумя методами является концептуальным и стилистическим: вы используете forEach
, когда хотите сделать что-то для или с для каждого элемента массива (делая " с "это то, что пост, на который вы ссылаетесь, подразумевается под" побочными эффектами ", я думаю), тогда как вы используете map
, когда хотите скопировать и преобразовать каждый элемент массива (без изменения оригинал).
Поскольку и map
, и forEach
вызывают функцию для каждого элемента в массиве, и эта функция определяется пользователем, вы почти ничего не можете сделать с одним, а не с другим. Можно, хотя и некрасиво, использовать map
для изменения массива на месте и / или сделать что-то с элементами массива:
var a = [{ val: 1 }, { val: 2 }, { val: 3 }];
a.map(function(el) {
el.val++; // modify element in-place
alert(el.val); // do something with each element
});
// a now contains [{ val: 2 }, { val: 3 }, { val: 4 }]
Но гораздо понятнее и понятнее, чем вы собираетесь использовать forEach
:
var a = [{ val: 1 }, { val: 2 }, { val: 3 }];
a.forEach(function(el) {
el.val++;
alert(el.val);
});
Особенно если, как это обычно бывает в реальном мире, el
является полезной для восприятия человеком переменной:
cats.forEach(function(cat) {
cat.meow(); // nicer than cats[x].meow()
});
Таким же образом вы можете легко использовать forEach
для создания нового массива:
var a = [1,2,3],
b = [];
a.forEach(function(el) {
b.push(el+1);
});
// b is now [2,3,4], a is unchanged
Но лучше использовать map
:
var a = [1,2,3],
b = a.map(function(el) {
return el+1;
});
Также обратите внимание на то, что, поскольку map
создает новый массив, он, вероятно, подвергается как минимум некоторому снижению производительности / памяти, когда все, что вам нужно, это итерация, особенно для больших массивов - см. http://jsperf.com/map-foreach
Что касается того, почему вы хотите использовать эти функции, они полезны в любое время, когда вам нужно выполнить манипуляции с массивами в javascript, что (даже если мы просто говорим о javascript в среде браузера) довольно часто, почти в любое время вы получаете доступ к массиву, который вы не записываете вручную в своем коде. Возможно, вы имеете дело с массивом элементов DOM на странице, или данными, извлеченными из запроса AJAX, или данными, введенными пользователем в форму. Один из распространенных примеров, с которыми я сталкиваюсь - это извлечение данных из внешнего API, где вы можете использовать map
для преобразования данных в нужный вам формат, а затем использовать forEach
для итерации по вашему новому массиву в порядке показать его вашему пользователю.
Голосованный ответ (от Кена Редлера) вводит в заблуждение.
побочный эффект в информатике означает, что свойство функции / метода изменяет глобальное состояние [wiki]. В некотором узком смысле это может также включать чтение из глобального состояния, а не из аргументов. При императивном или ОО-программировании побочные эффекты появляются в большинстве случаев. И вы, вероятно, используете это, не осознавая.
Существенная разница между forEach
и map
заключается в том, что map
выделяет память и сохраняет возвращаемое значение, а forEach
выбрасывает его. См. emca spec для получения дополнительной информации.
Что касается причины, по которой люди говорят, что forEach
используется, когда вы хотите побочный эффект, заключается в том, что возвращаемое значение forEach
всегда undefined
. Если он не имеет побочного эффекта (не изменяет глобальное состояние), то функция просто тратит время процессора. Оптимизирующий компилятор исключит этот блок кода и заменит его конечным значением (undefined
).
Кстати, следует отметить, что JavaScript не имеет ограничений на побочные эффекты. Вы все еще можете изменить исходный массив внутри map
.
var a = [1,2,3]; //original
var b = a.map( function(x,i){a[i] = 2*x; return x+1} );
console.log("modified=%j\nnew array=%j",a,b);
// output:
// modified=[2,4,6]
// new array=[2,3,4]
Вы можете использовать map
, как если бы это было forEach
.
Однако, он сделает больше, чем должен.
scope
может быть произвольным объектом; это ни в коем случае не обязательно this
.
Что касается того, есть ли реальные применения для map
и forEach
, также спросите, есть ли реальные применения для циклов for
или while
.
Хотя все предыдущие вопросы верны, я определенно сделал бы другое различие. Использование map
и forEach
может подразумевать намерение.
Мне нравится использовать map
, когда я просто каким-то образом преобразовываю существующие данные (но хочу убедиться, что исходные данные не изменились.
Мне нравится использовать forEach
, когда я изменяю коллекцию на месте.
Например,
var b = [{ val: 1 }, { val: 2 }, { val: 3 }];
var c = b.map(function(el) {
return { val: el.val + 1 }; // modify element in-place
});
console.log(b);
// [{ val: 1 }, { val: 2 }, { val: 3 }]
console.log(c);
// [{ val: 3 }, { val: 4 }, { val: 5 }]
Мое эмпирическое правило заключается в том, чтобы при map
вы всегда создавали какой-то новый объект / значение для возврата для каждого элемента списка источников и возвращали его, а не просто выполняли какую-либо операцию над каждым элемент.
Если у вас нет реальной необходимости изменять существующий список, на самом деле нет смысла изменять его на месте и лучше вписываться в функциональные / неизменяемые стили программирования.
Это красивый вопрос с неожиданным ответом.
Нижеследующее основано на официальном описании Array.prototype.map()
.
Ничего , что forEach()
не может сделать, чего не может map()
. То есть map()
является строгим супернабором из forEach()
.
Хотя map()
обычно используется для создания нового массива, он может также использоваться для изменения текущего массива. Следующий пример иллюстрирует это:
var a = [0, 1, 2, 3, 4], mapped = null;
mapped = a.map(function (x) { a[x] = x*x*x; return x*x; });
console.log(mapped); // logs [0, 1, 4, 9, 16] As expected, these are squares.
console.log(a); // logs [0, 1, 8, 27, 64] These are cubes of the original array!!
В приведенном выше примере a
удобно установить таким образом, чтобы a[i] === i
для i < a.length
. Несмотря на это, он демонстрирует мощь map()
и, в частности, его способность изменять массив, в котором он вызывается.
< Сильный > Note1 :
Официальное описание подразумевает, что map()
может даже изменить length массив, в котором он вызывается! Однако я не вижу (веских) причин для этого.
< Сильный > Примечание2 :
В то время как map()
карта является надмножеством forEach()
, forEach()
все равно следует использовать там, где нужно изменить данный массив. Это проясняет ваши намерения.
Надеюсь, это помогло.
TL; DR ответ -
Карта всегда возвращает другой массив.
ForEach нет. Вам решать, что он делает. Верните массив, если хотите, или сделайте что-нибудь еще, если нет.
Гибкость желательна в определенных ситуациях. Если это не то, с чем вы имеете дело, используйте карту.
Похожие вопросы
Связанные вопросы
Новые вопросы
javascript
По вопросам программирования на ECMAScript (JavaScript / JS) и его различных диалектах / реализациях (кроме ActionScript). Включите все соответствующие теги в свой вопрос; например, [node.js], [jquery], [json] и т. д.