2012-01-08 3 views
189

Я ищу способ остановить итерации метода underscore.js _.each(), но не могу найти решение. jQuery .each() можно сломать если сделаете return false.Как разбить функцию _.each в underscore.js

Есть ли способ остановить подчеркивание каждого()?

_([1,2,3]).each(function(v){ 
    if (v==2) return /*what?*/; 
}) 
+4

Я не думаю, что это возможно, потому что родной 'функция forEach' не поддерживает эту функцию, либо. –

+8

Обычно, когда вы используете 'each' с закрытием (на большинстве языков), вы хотите сначала отфильтровать список. Таким образом, вам не нужно беспокоиться о том, чтобы сломать его. Вообще говоря, если вам нужно рано расколоться с итерации, возможно, вы по-другому можете это сделать. –

+0

[Здесь] (http://stackoverflow.com/questions/1766941/groovy-how-to-exit-each-loop/1767046) [пара] (http://stackoverflow.com/questions/3049790/break -from-groovy-each-clos) связанные вопросы для Groovy, где поведение (невозможность удобно сломаться от закрытия каждого) похоже на JavaScript. –

ответ

250

Вы не можете разорвать от each метод, он эмулирует поведение родного forEach метода, а родной forEach не предусматривает, чтобы избежать петли (кроме метания исключения).

Однако вся надежда не потеряна! Вы можете использовать метод Array.every. :)

Из этой ссылке:

every один раз выполняет предоставленный callback функцию для каждого элемента, присутствующего в массиве, пока не найдет тот, где callback возвращает ложное значение. Если такой элемент найден, метод every немедленно возвращает значение false.

Другими словами, вы могли бы сделать что-то свернутый, как это (link to JSFiddle):

[1, 2, 3, 4].every(function(n) { 
    alert(n); 
    return n !== 3; 
}); 

Это предупредит 1 через 3, а затем "перерыв" из цикла.

Вы используете underscore.js, так что вы будете рады узнать, что он делает обеспечивают every метод, который они называют его every, но как ссылка упоминает, они также предоставляют псевдоним называется all.

+2

Имеет ли underscore.js реализацию для этого? –

+1

@FelixKling, да. Я добавил это к моему ответу. – aeskr

+1

вы можете использовать _.every или _.all в настоящее время –

3

Вы не можете разбить в подчеркивании на forEach, как он эмулирует ECMAScript 5 родное поведения.

3

Возможно, вы хотите использовать any() или find(), что прекратит обработку при выполнении условия.

2

Я считаю, что если ваш массив был фактически объектом, который вы могли бы вернуть, используя пустой объект.

_.({1,2,3,4,5}).each(function(v){ 
    if(v===3) return {}; 
}); 
+0

Это происходит только с EcmaScript v <5 в качестве сравнения, которое подчеркивает, чтобы проверить, возвращает ли вы пустой объект в предоставленной альтернативе forEach, только когда родной не доступен. –

1

Обновление:

Вы можете на самом деле «перерыв», бросая ошибку внутри и ловить его снаружи: что-то вроде этого:

try{ 
    _([1,2,3]).each(function(v){ 
    if (v==2) throw new Error('break'); 
    }); 
}catch(e){ 
    if(e.message === 'break'){ 
    //break successful 
    } 
} 

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

+0

Люблю, как я получаю так много голосов за это, и этот парень получает целую нагрузку для своего http://stackoverflow.com/a/2641374/674720 –

+1

Я опаздываю на вечеринку, но заметьте, что парень не только сказал, что вы предложили, но предложил еще две альтернативы (и более подходит).Единственный предлагал «взломать», если пользователь во что-то хочет этого. Вместо этого вы предлагали только уродливый хак. – Areks

+0

спасибо за отзыв –

65

Обновление:

_.найти бы лучше, так как он ломает из цикла, когда элемент найден:

var searchArr = [{id:1,text:"foo"},{id:2,text:"bar"}]; 
var count = 0; 
var filteredEl = _.find(searchArr,function(arrEl){ 
       count = count +1; 
       if(arrEl.id === 1){ 
        return arrEl; 
       } 
      }); 

console.log(filteredEl); 
//since we are searching the first element in the array, the count will be one 
console.log(count); 
//output: filteredEl : {id:1,text:"foo"} , count: 1 

** Старый **

Если вы хотите условно вырваться из петли, использовать _.filter API вместо каждого. Вот фрагмент кода

var searchArr = [{id:1,text:"foo"},{id:2,text:"bar"}]; 
var filteredEl = _.filter(searchArr,function(arrEl){ 
        if(arrEl.id === 1){ 
         return arrEl; 
        } 
       }); 
console.log(filteredEl); 
//output: {id:1,text:"foo"} 
+1

это не сломает цикл - он просто фильтрует массив. представьте, что у вас не было 2, а 20 000 предметов в массиве. вы регистрируете только вывод, который вы отправили, но цикл будет работать 20 000 раз :( – pkyeck

+0

@pkyeck, вы правы, может быть _.find лучше, чем _.фильтр, когда он ломается после обнаружения элемента, вот скрипка: http://jsfiddle.net/niki4810/9K3EV/ – Nikhil

+2

Я думаю, что этот ответ должен быть помечен как правильный. '_.find' выполняет именно то, что задано: перебирать список до тех пор, пока обратный вызов не вернет« true ». –

6
_([1,2,3]).find(function(v){ 
    return v if (v==2); 
}) 
2

Это также хорошо отметить, что каждый цикл не может быть нарушена из - до перерыва использовать _.find вместо этого.

http://underscorejs.org/#each

13

Вы можете посмотреть на _.some вместо _.each. _.some останавливает перемещение списка, когда предикат является истинным. Результат (ы) может храниться во внешней переменной.

_.some([1, 2, 3], function(v) { 
    if (v == 2) return true; 
}) 

См http://underscorejs.org/#some

0

работал в моем случае

var arr2 = _.filter(arr, function(item){ 
    if (item == 3) return item; 
}); 
Смежные вопросы