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

Спасибо за любой ответ.

92
JohnMerlino 14 Июн 2010 в 03:58

8 ответов

Лучший ответ

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

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

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

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

93
Ken Redler 11 Янв 2017 в 15:22

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

0
Markku Uttula 4 Янв 2016 в 01:54

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

65
nrabinowitz 20 Фев 2015 в 00:42

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

побочный эффект в информатике означает, что свойство функции / метода изменяет глобальное состояние [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]
16
jeffreysbrother 14 Авг 2017 в 19:41

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

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

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

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

3
wombleton 14 Июн 2010 в 01:07

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

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

1
maschwenk 6 Апр 2016 в 05:59

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

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

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

6
Sumukh Barve 29 Июл 2014 в 08:15

TL; DR ответ -

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

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

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

0
charsi 11 Апр 2018 в 21:11