какая польза от метода javascript forEach (эта карта не может сделать)? - PullRequest
87 голосов
/ 14 июня 2010

Единственное отличие, которое я вижу в карте и 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 ]

91 голосов
/ 14 июня 2010

Существенное отличие между map и forEach в вашем примере состоит в том, что forEach работает с исходными элементами массива, тогда как map явно возвращает новый массив в результате.

С forEach вы предпринимаете некоторые действия с - и, возможно, изменяете - каждый элемент в исходном массиве. Метод forEach запускает функцию, которую вы предоставляете для каждого элемента, но ничего не возвращает (undefined). С другой стороны, map проходит по массиву, применяет функцию к каждому элементу, а выдает результат в виде нового массива .

«Побочный эффект» с forEach заключается в том, что исходный массив изменяется. «Отсутствие побочного эффекта» с map означает, что при идиоматическом использовании исходные элементы массива не изменены; новый массив - это взаимно-однозначное сопоставление каждого элемента в исходном массиве - преобразование сопоставления является предоставленной вами функцией.

Тот факт, что база данных не задействована, не означает, что вам не придется оперировать структурами данных, что, в конце концов, является одной из сущностей программирования на любом языке. Что касается вашего последнего вопроса, ваш массив может содержать не только числа, но и объекты, строки, функции и т. Д.

66 голосов
/ 08 февраля 2011

Основное различие между этими двумя методами является концептуальным и стилистическим: вы используете 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 для итерации по вашему новому массиву, чтобы отобразить его вваш пользователь.

14 голосов
/ 26 мая 2013

Голосованный ответ (от Кена Редлера) вводит в заблуждение.

A побочный эффект в информатике означает, что свойство функции / метода изменяет глобальное состояние [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]
6 голосов
/ 29 июля 2014

Это красивый вопрос с неожиданным ответом.

Нижеследующее основано на официальном описании 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() и, в частности, способность изменять массив, в котором он вызывается.

Примечание 1:
Официальное описание подразумевает, что map() может даже изменить длину массива, в котором он вызывается! Однако я не вижу (веских) причин для этого.

Примечание 2:
В то время как map() map - это супер-набор forEach(), forEach() все равно следует использовать там, где нужно изменить данный массив. Это проясняет ваши намерения.

Надеюсь, это помогло.

3 голосов
/ 14 июня 2010

Вы можете использовать map, как если бы это было forEach.

Однако он сделает больше, чем должен.

scope может быть произвольным объектом; это не обязательно this.

Что касается того, есть ли реальные применения для map и forEach, также спросите, есть ли реальные применения для циклов for или while.

1 голос
/ 06 апреля 2016

Хотя все предыдущие вопросы верны, я определенно сделал бы другое различие. Использование 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 вы всегда создавали какой-то новый объект / значение для возврата для каждого элемента списка источников и возвращали его, а не просто выполняли какую-либо операцию над каждым элемент.

Если у вас нет реальной необходимости изменять существующий список, на самом деле нет смысла изменять его на месте, и он лучше вписывается в функциональные / неизменные стили программирования.

0 голосов
/ 12 апреля 2018

TL; DR ответ -

Карта всегда возвращает другой массив.

forEach нет. Вам решать, что он делает. Верните массив, если хотите, или сделайте что-нибудь еще, если нет.

Гибкость желательна в определенных ситуациях. Если это не то, с чем вы имеете дело, используйте карту.

0 голосов
/ 04 января 2016

Еще раз, я чувствую себя некромантом, добавляющим ответ на вопрос, который был задан 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 написано, что я не думаю, что слишком много браузеров поддерживают пока (по крайней мере, полностью), но - мы добираемся. Если бы мне нужно было запустить его в браузере, я думаю, что это прошло бы хорошо.

...