Pull to refresh

Comments 36

Решил проверить последний пункт, чтобы выяснить, стоит ли игра свеч — код с filter+map мне визуально нравится намного больше, чем с reduce. Тестовый кейс, результаты в хроме на маке — reduce в 4 раза медленнее.

/здесь недовольное бормотание про преждевременную оптимизацию и вредные советы/
Нахлобучил туда же еще for...of и обычный цикл — на моей машине оба варианта быстрее, чем filter+map, но не намного. Обычный цикл предсказуемо впереди всех.

Подозреваю, что filter+map не сильно отстает просто потому, что конструкция очень часто встречается и, видимо, очень сильно оптимизирована в V8.
в лисе все варианты примерно одинаковы, кроме тормозного concat().

в хромом reduce обогнал даже цикл.

как всегда отличился edge. в нем for...of на 65% тормознее обычного for. *рукалицо*

возможно, современные движки преобразуют подобные простые примеры в обычный цикл. или новые массивы так быстро создаются? правда, не знаю, насколько актуален массив из 3-х элементов.
Можете добавить такой вариант для сравнения?
const processed = characters
.reduce((acc, character) => {
return character.env === 'marvel'
? (acc.push(Object.assign({}, character, { alsoSeenIn: ['Avengers'] })), acc)
: acc;
}, [])
Добавил. Результаты уравнялись :)
Все равно выходит, что на массивах подобной длины смысла использовать reduce особо нет.

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


const processed = [];

characters.forEach((el) => {
   if(el.env === 'marvel') {
      processed.push(Object.assign({}, characters[i], { alsoSeenIn: ['Avengers'] }));
   }
});
Не только же хромом единым. В Edge reduce не самый медленный, а вот for..of на удивление у меня тормозит знатно. В FF последнем разрыв уже не такой большой.

Если писать reduce так как автор, то ни о какой производительности и речи не может быть. Из статьи в статью одна и та же ошибка. Вот такое решение:


reduce((arr, el) => arr.concat(...), [])

в каждой итерации reduce arr.concat создаёт НОВЫЙ МАССИВ! Это бессмысленное перекладывание байтов! Big O такого решения чудовищно! Чем больше наш arr.length, тем чудовищнее будет результат.

Это он про иммутабильность просто читал где-то, но ничего не понял))))

Шипилева на вас нет!


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


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


P.S. Ещё раз повторюсь, думаю, что на фронте не должно возникать ситуаций, когда это реально критично. Может какая-то виртуальная реальность или игры, но тогда императивный стиль в помощь.

indexOf vs includes
А чего так завязывать на возврат логическое ответа?!
И если так уж надо логический ответ:
console.log(!!~characters.indexOf('hulk'));
// true
console.log(!!~characters.indexOf('batman'));
// false


filter vs find
В варианте с find потерян один вариант в выборке, значит результат работы кода эквивалентен. А значит подобный пример и замена вообще неуместны.

ИМХО поиск и решение проблем там где их нет. Цель подобных примеров: смотрите у нас появились новые методы, давайте их использовать везде. Может надо просто быть объективней.

Статья ради статьи…
Цель подобных примеров: смотрите у нас появились новые методы, давайте их использовать везде

Мне показалось наоборот.
: Смотрите, у нас появился метод, который проверяет есть ли элемент в массиве! Так давайте indexOf использовать по своему назначению (для получения индекса), а includes по своему (для определения, существует ли такой элемент).


А за вот такое неявное добро
!!~
надо наказывать.


Может надо просто быть объективней.

Как раз и получается, что нужно быть объективнее, и использовать методы по их назначению, а не получать массив элементов через filter только для того, чтобы получить один элемент.
Пример с reduce и map/filter плохой.

Скажите, а вы на полном серьёзе считаете что !!~indexOf и includes равно-уместны в реальном коде?

Нет конечно, я лишь обратил внимание что замена ради получения логического выражения это абсурд.
Статья ради статьи…
Ну вообще-то ради рекламы)
Какой-то неудачный пример reduce. reduce — это же не про filter+map в одном, это же про агрегацию — на входе итератор, на выходе одно значение:
let values = [3,2,60,4];
let sum = values.reduce((s,v)=>s+v);
//sum = 69

Метод универсальный, но использование его вместо filter/map/some/find — это всё равно, что использовать indexOf вместо includes, против чего выступают в начале статьи.
использование reduce как замена filter + map сильно (в 2 раза) помогает сократить количество итераций

Я немного ошибся с формулировкой, имею ввиду правильнее. Итераций будет столько же.


const processed = [];

characters.forEach((el) => {
   if(el.env === 'marvel') {
      processed.push(Object.assign({}, characters[i], { alsoSeenIn: ['Avengers'] }));
   }
});

но использование reduce через concat или https://habr.com/company/ruvds/blog/422091/#comment_19064761 мне кажется, как минимум не логично, т.к. код с forEach получается точно такой же, а в примере reduce используется тупо для интегрирования, с этой задачей справляется и forEach.

в данном контексте для меня reduce выглядит гораздо чище, хотя это вопрос вкуса :-)
Даже если допустить, что reduce работает в два раза быстрее, чем filter + map, то для большинства проектов — это все равно не нужная микро-оптимизация, которая вообще не будет заметна. А читаемость кода страдает.
Всегда нужно смотреть, какая получается выгода. Если элемент ищется один раз даже в очень большом массиве после клика пользователя, то пользователю абсолютно все равно, отработает код за 1 миллисекунду или за 100 миллисекунд, и в этих случаях лучше писать как удобно.

Когда же скорость по настоящему критична, например когда поиск происходит часто и много раз, то имеет смысл просто сразу индексировать массив и находить значения моментально. В случае когда необходимо булево значение вообще использовать Object или Set.

Случаев, когда замена indexOf на includes или filter + map на reduce принесет ощутимую пользовательскому глазу выгоду не так много, к тому же методы разработчиками браузеров постоянно допиливаются и показатели меняются. Можно вдруг обнаружить, что filter + map в ряде случаев быстрее, чем reduce, а простой перебор цикла еще быстрее. Посему для кода использовать что более удобно — например includes использовать просто логичней и красивей, когда нужно булево значение, чем indexOf !== false, а для быстрого поиска использовать индексацию.
Ну, если говорить о скорости — while/for+break будет в любом случае быстрее чем любой функциональный вариант (filter/some e.t.c.). Но это императивный код.

С includes все еще есть проблема, что babel не транспайлит его во что-то более менее адекватное.
image
А это EcmaScript 2016. Поэтому нужно быть очень аккуратным и использовать его только там где вы уверены будет поддержка ES7 (сервер/приложение для вечнозеленых браузеров).

Дык Babel и не должен транспайлить includes. Это задача полифилов. Собственно использование одного только транспайлера, без связки полифилов, это как-минимум очень странно :)

Если можете поясните новичку почему так acc.push(Object.assign({}, character, { alsoSeenIn: ['Avengers'] }) не работае, а вот так (acc.push(Object.assign({}, character, { alsoSeenIn: ['Avengers'] })), acc) работает? Ведь acc это массив, но в первом варианте выдает ошибку что push is not a function. Заранее спасибо)

Всё просто:


// variant 1
return do1(), do2(), do3(), do4(), 5;

// variant 2
do1();
do2();
do3();
do4();
return 5;

Оба участка кода эквивалентны. Автор приведённой вами строки сэкономил символы используя "оператор запятую". Но имейте ввиду, что обычно за такой код "бьют", и никаких лишних мутных запятых в коде быть не должно.

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


По сути.


  1. "Замена indexOf() на includes()"
    Конечно, якобы второй метод лучше говорит сам за себя, но первый является общепринятым, отсюда, также понятным.


  2. "Использование метода find() вместо метода filter()" и "Замена метода find() на метод some()"
    Тут понятно, все зависит от того, что нужно сделать. Странное замечание в общем.


  3. "Использование метода reduce() вместо комбинации методов filter() и map()"
    Ну это вообще тупость, чувак явно дома забивает гвозди шуруповёртом (хотя может и шурупы им забивает).


Если вы знаете реально крутые посты, качественные переводы готовы неистово плюсовать — присылайте в личку, посмотрим.

А какая тематика интересна? И какой формат?

Интересны обучающие материалы по работе с языками программирования типа JS, по веб разработке, по администрированию и настройке виртуальных серверов, по установке и работе с различными программами на виртуальных серверах на ОС Windows Server или Linux
В общем присылайте в личку все, что вы считаете интересным для перевода. Достаточно просто ссылки на материал.
Sign up to leave a comment.