как сломать функцию _.each в underscore.js


200

Я ищу способ остановить итерации _.each()метода underscore.js , но не могу найти решение. JQuery .each()может сломаться, если вы это сделаете return false.

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

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

4
Я не думаю, что это возможно, потому что нативная forEachфункция также не предлагает эту функцию.
— Феликс Клинг

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

Вот пара связанных вопросов для Groovy, где поведение (неспособность удобно отделиться от eachзамыкания) похоже на JavaScript.
— Роб Хруска

@Dmitry_F, как уже отмечали другие, вы не можете делать именно то, что вы просите. Но, как я продемонстрировал, вы можете использовать, Array.everyчтобы имитировать поведение, которое вы хотите.
— aeskr

@Rob. Приветствия. Первый комментарий действительно полезен. На самом деле, я мог сделать это по-другому.
— net.uk.sweet

Ответы:


267

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

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

По этой ссылке:

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

Другими словами, вы можете сделать что-то запутанное, как это ( ссылка на 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

2
сейчас (05/2013) нет ни метода, _.every()ни _.all()метода для массивов в подчеркивании - так что придерживайтесь Array.every().
— pkyeck

3
Это будет работать, но это обычная причина для использования every. Так что следите за удобочитаемостью.
— evanrmurphy

3
Подчеркнутые документы для _.each()имеют примечание конкретно о том факте, что вы не можете выйти из цикла, и рекомендуем использовать _.find()вместо этого. http://underscorejs.org/#each
— blatt

70

Обновить:

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

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 вместо _.each. Вот фрагмент кода

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

@pkyeck вы правы, может быть _.find лучше _.filter , как он ломает после elemnt найдено, здесь скрипки: jsfiddle.net/niki4810/9K3EV
— Нихилу

2
Я думаю, что этот ответ должен быть помечен как правильный. _.findделает именно то, что запрашивается: перебирать список до тех пор, пока обратный вызов не вернется true.
— Фабьен Кватраво

Голосовали за этот ответ, потому что принятый ответ (Array.every) не будет работать с объектами, но _.find () будет работать.
— Мэтт

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

15

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

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

Смотрите http://underscorejs.org/#some



3

Может быть, вы хотите Underscore any () или find (), который остановит обработку при выполнении условия.



3

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


2

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

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

Это происходит только с 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
  }
}

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


Мне нравится, что за это я получил так много голосов "за", и этот парень получил целую
— кучу

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

0

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

var arr2 = _.filter(arr, function(item){
    if ( item == 3 ) return item;
});
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.