Frontender Magazine

Во все тяжкие (Циклы в библиотеках JavaScript)

Я был достаточно удивлён, когда обнаружил несовпадения в поведении наиболее популярных библиотек JavaScript, в том, как они обрабатывают циклы each и forEach. В этой статье сравниваются:

Цикл forEach, встроенный в JavaScript

Библиотеки JavaScript важны (например, jQuery, Lo-Dash, Underscore), но в случае функциональных циклов (forEach и each) они становятся причиной путаницы (цикл for можно прервать при помощи break). Рассмотрим пример применения нативного для JavaScript метода forEach:

[1,2].forEach(function(v){
  alert(v);
  return false;
})

Этот код покажет два окошка alert. Попробуйте сами на JSFiddle.

Такое поведение вполне ожидаемо, потому как на каждой итерации мы вызываем функцию заново. В отличие от кода for (var i=0; i<arr.length; i++) {}, где нет никаких функций и итераторов.

Однако, в Lo-Dash и jQuery похожий код разрывает цикл!

Прерываемый цикл each в Lo-Dash

При использовании Lo-Dash подобный код с each вызовет только один alert:

_.each([1,2],function(v){
  alert(v);
  return false;
})

Попробуйте сами запустить этот код на JSFiddle.

Прерываемый цикл each в jQuery

У jQuery похожее поведение, следующий код вызовет только первый alert:

$.each([1,2],function(i, v){
  alert(v);
  return false;
})

Попробуйте сами на JSFiddle.

Неразрывный цикл each в Underscore.js

Чтобы всё усложнить, Underscore.js и Backbone.js остаются верными духу нативного forEach в JavaScript.

В Underscore.js each проходит по всем элементам и не прерывается:

_.each([1,2],function(v){
  alert(v);
  return false;
})

Попробуйте на JSFiddle.

Неразрывный цикл forEach в Underscore.js

Просто ради приличия я проверил также forEach() в underscore. Он, ожидаемо, ведёт себя так же, как нативный forEach(): два вызова alert!

Код с применением forEach() библиотеки Underscore:

_.forEach([1,2],function(i, v){
  alert(v);
  return false;
})

Проверьте сами на JSFiddle.

Разница между Lo-Dash и Underscore, которая может поломать ваш код

Итог этой короткой статьи: Lo-Dash не то же самое, что Underscore, при условии, что не используется особая версия, совместимая с Underscore. Спасибо Джону-Дэвиду Далтону (@jdalton), что обратил на это моё внимание:

@azat_co Всё верно, Lo-Dash не эквивалентная замена, если только не используется билд Lo-Dash.underscore.js (на него есть ссылка на главной). То же и в cdnjs. — Джон-Дэвид Далтон (@jdalton) 22 ноября 2013

P.S.: forEach в Underscore.js лучше совместим с браузерами, чем нативный forEach, потому что последний был относительно недавно добавлен в API JavaScript и не поддерживается более старыми браузерами.

Если вы заметили ошибку, вы всегда можете отредактировать статью, создать issue или просто написать об этом Антону Немцеву в skype ravencry.

Azat Mardan
Автор:
Azat Mardan
GitHub:
azat-co
Сaйт:
http://azat.co/
Twitter:
@azat_co
Антон Хлыновский
Переводчик:
Антон Хлыновский
GitHub:
subzey
Twitter:
@subzey

Комментарии (4 комментария, если быть точным)

Автар пользователя
mistakster

Если бы Азат заглянул в исходный код Underscore.js, то увидел бы, что each и forEach — это одно и то же. И, конечно, метод повторяет нативную реализацию потому, что вызывает её внутри себя.

Автар пользователя
A

В любой непонятной ситуации читай исходный код :)

Автар пользователя
tryasko

Непонятно причем здесь Backbone.js? У него нет собственной реализации метода forEach(each).

Автар пользователя
evilandfox

evilandfoxСегодня в 02:57 Что тут удивительного? В lodash вполне разумная возможность прерывания цикла возвратом false. Вебмастер при переходе с underscore на lodash наверняка догадается изучить вопросы совместимости и установит lodash с совсестимостью underscore. Да и по сути он не обязан его поддерживать, это же разные библиотеки.