Когда/зачем использовать карту/уменьшить для циклов

Итак, я впервые сталкиваюсь с манипуляциями с объектами в JavaScript, и у меня есть вопрос, на который мне интересно, может ли кто-нибудь ответить.

Когда у меня есть объект, с которым я хочу манипулировать, я мог бы сделать что-то в пределах нескольких вложенных циклов, однако есть функции, встроенные в JavaScript, такие как map/reduce/filter и библиотеки, такие как lodash/underscore.

Я предполагаю, что последние (map/reduce/filter и библиотеки) - лучшая практика, но мне просто интересно, почему.

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

Извините, кода нет. Я был бы очень признателен, если бы кто-нибудь помог мне понять больше здесь.

Изменить - так что взяв из примеров для map()

Я мог бы взять пример для javascript.map

 var kvArray = [{key:1, value:10}, {key:2, value:20}, {key:3, value: 30}];
var reformattedArray = kvArray.map(function(obj){ 
var rObj = {};
rObj[obj.key] = obj.value;
return rObj;
});

Я мог бы сделать что-то вроде

   var kvArray = [{key:1, value:10}, {key:2, value:20}, {key:3, value: 30}];
var reformattedArray = [];

for(var object in kvArray){
  //combine both values into object inside of kvArray[object]);
 };

намного меньше кода - но какие-либо другие преимущества, о которых стоит знать?

Ответ 1

Я знаю, что отвечаю на старый ответ, но просто хотел указать на будущих читателей.

Функции сокращения карт и фильтрации происходят из мира функционального программирования.

Это встроенные операторы первого класса в таких языках, как Lisp, Haskell и др. (Ml?). Функциональные языки, как правило, предпочитают запускать операторы над неизменяемыми данными, а не заставлять код работать с данными для работы с ними (скажем, циклами). Таким образом, они предоставляют более простые, но мощные интерфейсы, такие как отображение, фильтрация и уменьшение по сравнению с предоставлением циклов и циклов while.

Это также помогает им удовлетворить другие требования, такие как неизменность и т.д. Именно поэтому карты возвращают вам новую карту вместо того, чтобы поменять старую. Они очень хороши с точки зрения параллелизма, хотя они могут быть медленнее в определенных контекстах.

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

Поскольку javascript пытается быть частично функциональным, предоставляя некоторые функциональные возможности функциональных языков программирования, возможно, имело бы смысл также реализовать в нем функции отображения, фильтрации и сокращения.

YMMV в зависимости от того, что вы делаете с инструментами, которые вам дают.

Если ваш код работает лучше с циклом for, сделайте это.

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

Мои 2 рупии

Ответ 2

Это похоже на вопрос, нравится ли мне баскетбол или футбол лучше. Оба имеют свои положительные результаты.

Если у вас 10 разработчиков, посмотрите на свой цикл for, 9 из 10 будут знать, что вы делаете сразу. Может быть, половина придется искать способ map(), но потом они также узнают, что происходит. Таким образом, в этом отношении цикл for легче читать другим.

С другой стороны, map() сохранит вам две или три строки кода.

Что касается производительности, вы обнаружите, что map() встроен с чем-то похожим на цикл for. Вы можете увидеть несколько миллисекунд разницы, когда дело доходит до скоростей производительности, если вы запускаете их через большие итерации; но они никогда не узнают конечного пользователя.

Ответ 3

.map() позволяет создавать новый массив, итерируя поверх исходного массива и позволяя вам выполнять какую-то функцию пользовательского преобразования. Выход из .map() - это новый массив.

var orig = [1,2,3,4,5];
var squares = orig.map(function(val) {
    return val * val;
});
console.log(squares);   // [1,4,9,16,25]

.reduce() позволяет вам перебирать массив, накапливающий один результат или объект.

var orig = [1,2,3,4,5];
var sum = orig.reduce(function(cum, val) {
    return cum + val;
}, 0);
console.log(sum);    // 15

Это специализированные итераторы. Вы можете использовать их, когда этот тип вывода именно то, что вы хотите. Они менее гибкие, чем цикл for (например, вы не можете остановить итерацию посередине, как вы можете, с помощью цикла for), но они меньше печатают для определенных типов операций и для людей, которые знают их, вероятно, немного легче увидеть намерение кода.

Я сам не тестировал производительность .map() и .reduce() по сравнению с циклом for, но видел тесты для .forEach(), которые показали, что .forEach() на самом деле медленнее в некоторых браузерах. Возможно, это связано с тем, что каждая итерация цикла с помощью .forEach() должна вызывать функцию обратного вызова, тогда как в обычном цикле for вам не нужно выполнять такой вызов функции (код может быть непосредственно встроен там). В любом случае редко бывает, что этот различие в производительности действительно значим, и вы обычно должны использовать любую конструкцию, которая упрощает и упрощает ведение кода.

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


Еще одно преимущество цикла for заключается в том, что его можно использовать с подобными массиву объектами, такими как HTMLCollection, которые не являются фактическими массивами и, следовательно, не имеют таких методов, как .reduce() и .map().

Ответ 4

Наткнулся на это, пока искал что-то другое. Таким образом, пытаясь ответить на него, даже если это старая тема, поскольку понятия применяются независимо от того, что.

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

Но есть и другие преимущества таких функций, как forEach, map, redu и т.д. (Пусть они называются функциональными методами). Это в основном читабельность, ремонтопригодность.

Ниже приведены некоторые недостатки цикла

  1. Вводит новые переменные в область видимости, только для счетчика/итерации
  2. Трудно исправить ошибки из-за непреднамеренных изменений переменных счетчика. Это становится более сложным, и вероятность ошибиться увеличивается с увеличением числа циклов с входными циклами.
  3. Разработчики имеют привычку использовать переменные цикла как i, j, k. Очень легко потерять счет того, какой счетчик и какой внутренний цикл выполняет код, как только цикл увеличивает определенные строки кода.
  4. С ES6 у нас есть по крайней мере ограниченная/локальная область действия, введенная 'let'. Но раньше переменные, введенные циклом for, имели область действия функции, вызывая еще больше случайных ошибок

Чтобы избежать всего этого, предлагается использовать такие функции, как forEach, map, reduction, когда вы знаете, что нужно делать (не забывайте, что большинство из этих функциональных методов предлагают неизменность). Небольшая жертва с точки зрения производительности для лучшего и более сжатого кода.

В ES6 большинство функциональных методов поддерживаются самим языком. Они оптимизированы, и нам не нужно полагаться на такие библиотеки, как lodash (если не наблюдается серьезного увеличения производительности).

Ответ 5

forEach(): выполняет предоставленную функцию (обратный вызов) один раз для каждого элемента массива. Ничего не возвращает (не определено), но этому обратному вызову разрешено изменять вызывающий массив.

map(): выполняет предоставленную функцию (обратный вызов) один раз для каждого элемента массива и создает новый массив с результатами этого выполнения. Он не может изменить содержимое вызывающего массива.

Conclution Использование map(), когда вам необходимо вернуть новый массив, используйте forEach() или for когда вы хотите изменить исходный массив.