2013-06-28 2 views
4

В последней версии кода here с подчеркиванием, на линии 211, который читаетТребуется ли это или (||) утверждение?

result || (result = iterator.call(context, value, index, list))) return breaker; 

это или утверждение необходимо? Можно ли заменить

(result = iterator.call(context, value, index, list))) return breaker; // ? 

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

Обратите внимание, что оператор JavaScript или (||) возвращает первый операнд, если он правдивый, а второй операнд, если он ('он' является первым операндом) является ложным. Это прямо из Крокфорда, Хороших частей. Также отмечено, что || значения an или с правдой/ложью не соответствуют истинным/ложным значениям.

Вот весь метод воспроизведен из приведенной выше ссылке:

var any = _.some = _.any = function(obj, iterator, context) { 
    iterator || (iterator = _.identity); 
    var result = false; 
    if (obj == null) return result; 
    if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); 
    each(obj, function(value, index, list) { 
     if (result || (result = iterator.call(context, value, index, list))) return breaker; 
    }); 
    return !!result; 
    }; 
+1

Возможно, это для производительности? – NicoSantangelo

+2

Эта функция, которая содержит команду if, выполняется несколько раз и работает с одинаковым значением результата. Впервые это будет неверно. – ctn

+3

Результат сначала ложный, но может быть изменен на каждой итерации. Этот код предполагает, что результат будет изменен только один раз. Без || iterator.call будет выполняться на каждой итерации. – Tommi

ответ

3

Ответ: Да, он может быть оптимизирован в предложенном пути если это нативный код.

Для понимания того, что будет идти на давайте упростить этот код на то, что здесь имеет значение, первое:

var result = false; 
for (var i in obj) 
{ 
    if (result || (result = call(i))) 
     return; 
} 

Это означает, что если либо result уже не является ложным он вернется или если call() возвращает Недействительное значение возвращается. Поскольку результат изменяется только на call(), первая проверка на result является избыточной.

var result = false; 
for (var i in obj) 
{ 
    if (result = call(i)) 
     return; 
} 

Этот код будет возвращать как только call() поставил, не ложное значение.

Кроме того, поскольку each() функция библиотеки и OP возвращает breaker на найденный элемент

, что происходит на самом деле является:

var result = false; 
for (var i in obj) 
{ 
    if (result || (result = call(i))) 
     break; 
} 

В этом случае код по-прежнему может быть оптимизирован в предлагаемом пути до тех пор, пока используется функция library foreach. Цикл будет оставлен по найденному значению.

Сложная часть состоит в том, что each() является библиотечной функцией и использует функцию имитации тела петель. Возврат константы библиотеки breaker из функции body выйдет из цикла.

Как только each() решает использовать родной .forEach()код не может быть оптимизирован больше, так как .forEach() не поймет возвращаемое значение breaker! См. Комментарий thg435 для получения более подробной информации!

+0

Но, согласно [этой строке] (https://github.com/documentcloud/underscore/blob/master/underscore.js#L83), возвращается 'breaker' означает, что функция 'each' прекратит итерацию. – matehat

+0

@matehat Спасибо! Не заметил, что вертикальная полоса прокрутки в коде OPs будет редактировать. –

7

Это заставляет меня думать, что проверка result|| на всякий случай ... или для поддержки сред, где forEach определен (например, через прокладку), но some нет.

Как было отмечено в комментариях, опор Underscore на собственных методах зацикливания (forEach, map и друзья) не кажется, что блестящая идея, по нескольким причинам:

  • они slower, чем просто петли
  • вы не можете разбить (ну, вы мог с выделенным исключением, но подчеркивает не делает этого)
  • Array.prototype может быть подделана другим (злонамеренным или глупым) кодом
+0

О! Никогда об этом не думал! Когда «каждый» не был бы методом '_'? Я думаю, что я должен посмотреть на документы/код – Ian

+2

. Это не что иное, чем мое понимание. Очень легко сделать заказ, каждый из которых выполняется на порядок быстрее, чем встроенный, но подчеркивание возвращается к native, что не только значительно медленнее но также имеет значительно различную семантику. Иисус Христос, ПОЧЕМУ. – Esailija

+0

'each' - это метод подчеркивания с псевдонимом для native' forEach', если он существует –