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