如何在underscore.js中破坏_.each函数


200

我正在寻找一种方法来停止underscore.js _.each()方法的迭代,但是找不到解决方案。.each()如果这样做,jQuery 可能会崩溃return false

有没有一种方法可以停止在下划线each()?

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

4
我认为这是不可能的,因为本机forEach函数也不提供此功能。
菲利克斯·克林

8
通常,在each与闭包一起使用时(大多数语言),您要先过滤列表。这样,您就不必担心会被打破。一般而言,如果您需要从迭代中尽早休息,则可能采取了另一种方法。
罗布·赫鲁斯卡

这是 Groovy 的几个相关问题,其中的行为(无法方便地从each闭包中断开)类似于JavaScript。
罗布·赫鲁斯卡

正如其他人所指出的那样,@ Dmitry_F无法完全满足您的要求。但是正如我所展示的,您可以Array.every用来模拟所需的行为。
aeskr 2012年

@抢。干杯。首先评论真的很有帮助。确实,我本来可以有另外一种方式。
net.uk.sweet 2012年

Answers:


267

您无法脱离该each方法-它模拟了本机forEach方法的行为,并且本机forEach不提供转义循环(除了引发异常)。

但是,所有的希望并没有失去!您可以使用该Array.every方法。:)

从该链接:

everycallback对数组中存在的每个元素执行一次提供的函数,直到找到一个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 2012年

2
目前(2013年5月5日),下划线中_.every()没有_.all()用于数组的方法,也没有方法-请坚持使用Array.every()
pkyeck

3
这将起作用,但这是使用的常见原因every。因此,请注意可读性。
evanrmurphy 2014年

3
下划线的文档中_.each()有一条注释,专门说明了您不能脱离循环这一事实,建议您_.find()改用它。 http://underscorejs.org/#each
blatt 2015年

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,因为找到要素后它会中断,这是小提琴:jsfiddle.net/niki4810/9K3EV
Nikhil

2
我认为这个答案应该标记为正确的答案。_.find确实执行了所要求的:遍历列表直到回调返回true
Fabien Quatravaux

之所以投票选择此答案,是因为可接受的答案(Array.every)对对象不起作用,但是_.find()可以。
马特2013年

这就是文档中建议的内容:还要注意,不能打破每个循环,要打破就可以使用_.find。
shaharsol 2014年

15

您可以_.some代替查看_.each_.some谓词为true时,将停止遍历列表。结果可以存储在外部变量中。

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

参见http://underscorejs.org/#some



3

也许您要使用Underscore的any()或find(),它们将在满足条件时停止处理。




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
  }
}

显然,这与代码在循环中触发的任何其他异常有关,因此请谨慎使用!


爱我如何为此获得如此多的不赞成票,而这个家伙的stackoverflow.com/a/2641374/674720
bm_i 2014年

1
我参加聚会很晚,但请注意,那个家伙不仅说了您的建议,而且还提供了另外两种选择(更合适)。如果用户一定要的话,唯一会提供“ hack”。相反,您只提供了丑陋的hack。
Areks 2014年

0

就我而言

var arr2 = _.filter(arr, function(item){
    if ( item == 3 ) return item;
});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.