如何短路Array.forEach像调用break?

[1,2,3].forEach(function(el) { if(el === 1) break; }); 

我怎样才能在JavaScript中使用新的forEach方法?

没有内置的forEach 。 要中断执行,你将不得不抛出某种exception。 例如。

 var BreakException = {}; try { [1, 2, 3].forEach(function(el) { console.log(el); if (el === 2) throw BreakException; }); } catch (e) { if (e !== BreakException) throw e; } 

你可以使用每种方法:

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

对于旧的浏览器支持使用:

 if (!Array.prototype.every) { Array.prototype.every = function(fun /*, thisp*/) { var len = this.length; if (typeof fun != "function") throw new TypeError(); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this && !fun.call(thisp, this[i], i, this)) return false; } return true; }; } 

更多细节在这里 。

现在有一个更好的方法来在ECMAScript2015(又名ES6)中使用新的for循环来做到这一点。 例如,此代码不打印数字5之后的数组元素:

 let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; for (let el of arr) { console.log(el); if (el === 5) { break; } } 

Array.prototype.forEach()的MDN文档引用:

注意:除了抛出一个exception之外, 没有办法停止或破坏一个forEach()循环。 如果您需要这样的行为, .forEach()方法是错误的工具 ,请使用简单的循环。 如果要为谓词testing数组元素并且需要布尔返回值,则可以使用every()some()来代替。

对于您的代码(在问题中),正如@bobince所build议的,使用Array.prototype.some()来代替。 它非常适合你的用例。

Array.prototype.some()为数组中的每个元素执行一次callback函数,直到findcallback函数返回一个真值(在转换为Boolean值时变为真的Boolean )为止。 如果find这样的元素, some()立即返回true。 否则, some()返回false。 callback仅针对已赋值的数组的索引进行调用; 对于已被删除或从未被赋值的索引,不会调用它。

考虑使用jqueryeach方法,因为它允许在callback函数中返回false:

 $.each(function(e, i) { if (i % 2) return false; console.log(e) }) 

Lodash库也提供了可以与map / reduce / fold等链接的takeWhile方法:

 var users = [ { 'user': 'barney', 'active': false }, { 'user': 'fred', 'active': false }, { 'user': 'pebbles', 'active': true } ]; _.takeWhile(users, function(o) { return !o.active; }); // => objects for ['barney', 'fred'] // The `_.matches` iteratee shorthand. _.takeWhile(users, { 'user': 'barney', 'active': false }); // => objects for ['barney'] // The `_.matchesProperty` iteratee shorthand. _.takeWhile(users, ['active', false]); // => objects for ['barney', 'fred'] // The `_.property` iteratee shorthand. _.takeWhile(users, 'active'); // => [] 

如果您想要使用Dean Edward的build议,并且抛出StopIteration错误而不必捕捉错误,就可以使用以下函数( 最初来自这里 ):

 // Use a closure to prevent the global namespace from be polluted. (function() { // Define StopIteration as part of the global scope if it // isn't already defined. if(typeof StopIteration == "undefined") { StopIteration = new Error("StopIteration"); } // The original version of Array.prototype.forEach. var oldForEach = Array.prototype.forEach; // If forEach actually exists, define forEach so you can // break out of it by throwing StopIteration. Allow // other errors will be thrown as normal. if(oldForEach) { Array.prototype.forEach = function() { try { oldForEach.apply(this, [].slice.call(arguments, 0)); } catch(e) { if(e !== StopIteration) { throw e; } } }; } })(); 

上面的代码将使您能够运行如下所示的代码,而无需执行您自己的try-catch子句:

 // Show the contents until you get to "2". [0,1,2,3,4].forEach(function(val) { if(val == 2) throw StopIteration; alert(val); }); 

一个重要的事情要记住的是,这只会更新Array.prototype.forEachfunction,如果它已经存在。 如果它不存在,它不会修改它。

不幸的是,在这种情况下,如果你不使用forEach会更好。 而是使用常规for循环,现在它将按照您所期望的那样工作。

 var array = [1, 2, 3]; for (var i = 0; i < array.length; i++) { if (array[i] === 1) break; } 

在你的代码示例中,它看起来像Array.prototype.find是你正在寻找: Array.prototype.find()和Array.prototype.findIndex()

 [1, 2, 3].find(function(el) { return el === 2; }); // returns 2 

简短的回答: for...break这个或改变你的代码,以避免forEach中断。 不要使用.some().every()来模拟for...break 。 重写你的代码,以避免for...break循环,或for...break 。 每当你使用这些方法for...break替代上帝杀死小猫。

很长的回答:

.some().every()都返回boolean值, .some()返回true如果传递的函数返回true任何元素,则返回false如果传递的函数返回false任何元素。 这就是这个function的意思。 使用函数并不意味着使用表格来代替CSS,因为这会让所有读取代码的人感到沮丧。

另外,使用这些方法的唯一可能的方法是for...break替代方法是使副作用(改变.some()callback函数外的一些variables),这与for...break没有多大区别。

所以,使用.some().every()作为for...break循环替代是不是没有任何副作用,这是不是很干净,然后for...break ,这是令人沮丧的,所以这不是更好。

你总是可以重写你的代码,这样就不需要for...break 。 您可以使用.filter()过滤数组,您可以使用.slice()等分割数组,然后使用.forEach().map()作为数组的一部分。

在另一个网站find这个解决scheme 您可以将forEach包装在try / catchscheme中。

 if(typeof StopIteration == "undefined") { StopIteration = new Error("StopIteration"); } try { [1,2,3].forEach(function(el){ alert(el); if(el === 1) throw StopIteration; }); } catch(error) { if(error != StopIteration) throw error; } 

更多细节在这里: http : //dean.edwards.name/weblog/2006/07/enum/

这只是我想出来解决这个问题…我很确定它解决了原来的问题,有问题:

 Array.prototype.each = function(callback){ if(!callback) return false; for(var i=0; i<this.length; i++){ if(callback(this[i], i) == false) break; } }; 

然后你可以用下面的方法来调用它:

 var myarray = [1,2,3]; myarray.each(function(item, index){ // do something with the item // if(item != somecondition) return false; }); 

在callback函数中返回false将导致中断。 让我知道如果这不实际工作。

为此,我使用nullhack ,它尝试访问null属性,这是一个错误:

 try { [1,2,3,4,5] .forEach( function ( val, idx, arr ) { if ( val == 3 ) null.NULLBREAK; } ); } catch (e) { // e <=> TypeError: null has no properties } // 

我想出了另一个概念:

 function forEach(array, cb) { var breakOnNext = false; function _break() { breakOnNext = true; } for (var i = 0, bound = array.length; i < bound; ++i) { if (breakOnNext) { break; } cb(array[i], i, array, _break); } } 

用法:

 forEach(['a','b','c','d'], function (e, i, array, _break) { console.log(e, i); if (e === 'b') { _break(); } }); 

可能需要一些调整,特别是支持对象属性迭代。

如果在迭代之后不需要访问数组,则可以通过将数组长度设置为0来保护数据。如果在迭代之后仍然需要,可以使用切片克隆它。

 [1,3,4,5,6,7,8,244,3,5,2].forEach(function (item, index, arr) { if (index === 3) arr.length = 0; }); 

或者用一个克隆:

 var x = [1,3,4,5,6,7,8,244,3,5,2]; x.slice().forEach(function (item, index, arr) { if (index === 3) arr.length = 0; }); 

这是一个更好的解决scheme,然后在你的代码中抛出随机错误。

如果你想保持你的forEach语法,这是一种保持高效的方式(虽然不如常规的循环)。 立即检查一个知道你是否想跳出循环的variables。

这个例子使用一个匿名函数在forEach周围创build一个函数作用域 ,你需要存储已经完成的信息。

 (function(){ var element = document.getElementById('printed-result'); var done = false; [1,2,3,4].forEach(function(item){ if(done){ return; } var text = document.createTextNode(item); element.appendChild(text); if (item === 2){ done = true; return; } }); })(); 
 <div id="printed-result"></div> 

这是一个for循环,但像forEach()一样维护循环中的对象引用,但是可以分解。

 var arr = [1,2,3]; for (var i = 0, el; el = arr[i]; i++) { if(el === 1) break; } 

使用array.prototype.every函数,它提供了实用程序来打破循环。 在此处查看示例Mozilla开发人员networking上的Javascript文档

同意@bobince,upvoted。

另外,FYI:

Prototype.js有这个用途:

 <script type="text/javascript"> $$('a').each(function(el, idx) { if ( /* break condition */ ) throw $break; // do something }); </script> 

$break会被内部的Prototype.js捕获和处理,打破“每个”循环但不会产生外部错误。

有关详细信息,请参阅Prototype.JS API 。

jQuery也有一个方法,只需在处理程序中返回false来尽早打破循环:

 <script type="text/javascript"> jQuery('a').each( function(idx) { if ( /* break condition */ ) return false; // do something }); </script> 

有关详细信息,请参阅jQuery API 。

这不是最有效的,因为你仍然循环所有的元素,但我认为这可能是值得考虑的非常简单:

 let keepGoing = true; things.forEach( (thing) => { if (noMore) keepGoing = false; if (keepGoing) { // do things with thing } }); 

你可以按照下面的代码为我工作:

  var loopStop = false; YOUR_ARRAY.forEach(function loop(){ if(loopStop){ return; } if(condition){ loopStop = true; } }); 

我知道这不正确的方式。 这不是打破循环。 这是一个Jugad

 let result = true; [1, 2, 3].forEach(function(el) { if(result){ console.log(el); if (el === 2){ result = false; } } }); 

我更喜欢用for in

 var words = ['a', 'b', 'c']; var text = ''; for (x in words) { if (words[x] == 'b') continue; text += words[x]; } console.log(text); 
 var Book = {"Titles":[ { "Book3" : "BULLETIN 3" } , { "Book1" : "BULLETIN 1" } , { "Book2" : "BULLETIN 2" } ]} var findbystr = function(str) { var return_val; Book.Titles.forEach(function(data){ if(typeof data[str] != 'undefined') { return_val = data[str]; } }, str) return return_val; } book = findbystr('Book1'); console.log(book);