Какое использование имеет метод javascript forEach (что карта не может сделать)?
Единственное отличие, которое я вижу в карте и 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.
Спасибо за любой ответ.
Ответы
Ответ 1
Существенное различие между map
и forEach
в вашем примере состоит в том, что forEach
работает с исходными элементами массива, тогда как map
явно возвращает новый массив.
С forEach
вы предпринимаете некоторые действия с - и, возможно, сменой - каждый элемент в исходном массиве. Метод forEach
выполняет функцию, которую вы предоставляете для каждого элемента, но ничего не возвращает (undefined
). С другой стороны, map
просматривает массив, применяет функцию к каждому элементу и испускает результат как новый массив.
"Боковой эффект" с forEach
заключается в том, что исходный массив изменяется. "Без побочного эффекта" с map
означает, что в идиоматическом использовании исходные элементы массива не изменяются; новый массив является взаимно однозначным отображением каждого элемента в исходном массиве - преобразование отображения является вашей предоставленной функцией.
Тот факт, что нет никакой базы данных, не означает, что вам не придется работать с структурами данных, что, в конце концов, является одной из сущностей программирования на любом языке. Что касается вашего последнего вопроса, ваш массив может содержать не только числа, но и объекты, строки, функции и т.д.
Ответ 2
Основное различие между этими двумя методами концептуально и стилистично: вы используете forEach
, когда хотите что-то делать или с каждым элементом массива (делать "с" - это то, что сообщение, которое вы цитируете, означало "side- эффекты", я думаю), тогда как вы используете 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
для итерации по вашему новому массиву, чтобы отобразить его на вашего пользователя.
Ответ 3
Проголосовавший ответ (от Кена Редлера) вводит в заблуждение.
A побочный эффект в информатике означает, что свойство функции/метода изменяет глобальное состояние [вики]. В некотором узком смысле это может также включать чтение из глобального состояния, а не из аргументов. При программировании с обязательным или OO побочные эффекты появляются чаще всего. И вы, вероятно, используете его, не осознавая.
Значимая разница между 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]
Ответ 4
Это прекрасный вопрос с неожиданным ответом.
Ниже приведено описание официального описания 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()
может даже изменить длину массив, на котором он вызывается! Однако я не вижу (хорошей) причины для этого.
Примечание2:
В то время как map()
map является супер-множеством forEach()
, forEach()
все равно должен использоваться там, где требуется изменение данного массива. Это делает ваши намерения ясными.
Надеюсь, что это помогло.
Ответ 5
Вы можете использовать map
, как будто это было forEach
.
Он будет делать больше, чем нужно.
scope
может быть произвольным объектом; это отнюдь не обязательно this
.
Что касается реальных приложений для map
и forEach
, а также спросить, существуют ли реальные применения для циклов for
или while
.
Ответ 6
Хотя все предыдущие вопросы верны, я определенно сделаю другое различие. Использование 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
вы всегда создаете новый объект/значение для возврата для каждого элемента исходного списка и возвращаете, а не просто выполняете некоторую операцию на каждый элемент.
Если у вас нет реальной необходимости изменять существующий список, на самом деле не имеет смысла изменять его на месте и лучше подходит для функциональных/неизменяемых стилей программирования.
Ответ 7
Снова я чувствую себя некромантом, добавляя ответ на вопрос, который был задан 5 лет назад (к счастью, есть довольно недавняя деятельность, поэтому я не единственный, кто беспокоит мертвых:).
Другие уже опубликовали ваш основной вопрос относительно разницы между функциями. Но для...
существуют ли какие-либо реальные применения этих методов в javascript (поскольку мы не обновляем базу данных), кроме как манипулировать такими цифрами:
... смешно спросить. Только сегодня я написал фрагмент кода, который присваивает ряд значений из регулярного выражения нескольким переменным, используя карту для преобразования. Он был использован для преобразования очень сложной текстовой структуры в визуализируемые данные... но для простоты я приведу пример с использованием строк даты, потому что они, вероятно, более знакомы для всех (хотя, если моя проблема действительно была с датами, вместо карты я бы использовал Date-object, который бы выполнил работу великолепно сам по себе).
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, что я не думаю, что слишком много поддержки браузеров (хотя бы полностью), но... мы добираемся туда. Если мне нужно было запустить его в браузере, я считаю, что это будет красиво перерисовываться.