[1,2,3].forEach(function(el) {
if(el === 1) break;
});
如何使用JavaScript中新的
forEach
方法来做到这一点?我已经尝试过return;
,return false;
和break
。 break
崩溃,而return
除了继续迭代之外什么也不做。#1 楼
break
中没有forEach
的内置功能。要中断执行,您将必须抛出某种异常。例如。 var BreakException = {};
try {
[1, 2, 3].forEach(function(el) {
console.log(el);
if (el === 2) throw BreakException;
});
} catch (e) {
if (e !== BreakException) throw e;
}
JavaScript异常不是很漂亮。如果您确实需要内部
for
,则传统的break
循环可能更合适。 使用
Array#some
相反,请使用
Array#some
: [1, 2, 3].some(function(el) {
console.log(el);
return el === 2;
});
之所以有效,是因为按数组顺序执行的任何回调一旦
some
返回true
,就会返回true
,从而使其余部分的执行短路。 > some
,其反every
(将在return false
处停止)和forEach
都是ECMAScript第五版方法,需要在缺少它们的浏览器中将它们添加到Array.prototype
中。评论
我认为这里有些“不错”,为什么不使用提前退出优化-
–chrismarx
16-3-2在16:47
感谢您的关注,这应该在答案中。无法理解为什么人们认为它的可读性较差。太棒了!
–卡尔·阿德勒(Karl Adler)
17 Mar 2 '17 at 14:15
Array#some的使用确实很棒。首先,它与大多数浏览器(包括ie9和firefox 1.5)的兼容性也非常好。我的示例用例将是在一个范围[a,b]的数组中找到索引,其中一个数字在下边界和上边界对之间,测试并在找到时返回true。 for..of将是次之的最佳解决方案,尽管仅适用于较新的浏览器。
– Sojimaxi
17年11月2日在16:08
绝对不要将异常处理用作控制流。期。
–坦率
17年11月10日在23:00
@frank我写了一个只有一个循环结构的esolang:永远。所有其他循环构造均由永久且适当的可迭代异常构成,例如ContinueIteration和StopIteration(break是要引发的宏)。一方面:永不。另一方面:总是。握在手上:有时?您评论中的“ PERIOD”暗示可能会引用您的建议吗?
– amcgregor
18-10-31在18:03
#2 楼
现在,在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;
}
}
从文档开始:
for ... in和for ... of语句都迭代某些内容。它们之间的主要区别在于它们迭代的内容。 for ... in语句以原始插入顺序遍历对象的可枚举属性。 for ... of语句遍历可迭代对象定义要迭代的数据。
迭代中需要索引吗?您可以使用
Array.entries()
:for (const [index, el] of arr.entries()) {
if ( index === 5 ) break;
}
评论
@superhero您可以在for ... of循环中获取元素的索引,只需使用条目即可。 for(someArray.entries()的(const [index,element]的常量){// ...}
– blackxored
18年1月19日在13:19
不建议不要将...用于数组吗?
– she7ata
18年6月20日在15:19
@emostafa对于数组不建议使用in循环是正确的,但这实际上是使用for循环的方法。
–canac
18年6月21日在17:33
这是“针对”的,这是一个非常干净的解决方案……但这也是ES6的功能,因此请注意,仅当您的环境针对ES6设置时,此功能才有效。
–乍得
19年7月16日在18:10
我发现自己经常使用此解决方案,并且也将其用于对象。使用对象,您可以执行Object.entries(myObject),然后完全像对数组使用for..in一样使用它。请注意,JS数组基本上是幕后对象:blog.niftysnippets.org/2011/01/myth-of-arrays.html
–安德鲁(Andrew)
19-10-25在17:44
#3 楼
您可以使用每种方法:[1,2,3].every(function(el) {
return !(el === 1);
});
ES6
[1,2,3].every( el => 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;
};
}
更多详细信息。
评论
现在在ES6中很干净-[1,2,3] .every(el => el!== 1)
–metame
17年1月4日在5:11
@Valdemar,但是是否能保证按顺序进行调用?
–起搏器
17-4-2在9:25
@Pacerier,您可以在ES6规范中看到索引k从0开始并以1递增的算法:http://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype。每一个
– XP1
17年6月26日在0:51
@ XP1,是否所有实施者都必须这样做?
–起搏器
17年8月7日在1:22
@Pacerier,是的,大多数流行的实现都能正常工作。如果您担心嵌入式实现,通常是Opera或Webkit。方法每个方法对数组中存在的每个元素以升序调用一次callbackfn,直到找到其中callbackfn返回false的元素为止。还要看步骤7。令k为0和8.e将k增加1。
–Valdemar_Rudolfovich
17年8月8日在6:39
#4 楼
从Array.prototype.forEach()
的MDN文档中引用:除了抛出
之外,没有其他方法可以通过引发异常来停止或中断
forEach()
循环。如果您需要这种行为,则.forEach()
方法是错误的工具,请改用普通循环。如果要为谓词测试数组元素并且需要布尔返回值,则可以改用every()
或some()
。对于代码(在问题中),如@所建议bobince,请改用
Array.prototype.some()
。它非常适合您的用例。Array.prototype.some()
对数组中存在的每个元素执行一次回调函数,直到找到其中回调返回真实值的值(当转换为Boolean
)。如果找到这样的元素,则some()
立即返回true。否则,some()
返回false。仅对具有分配值的数组索引调用回调;对于已删除或从未分配值的索引,不会调用它。评论
这是正确的答案。 “一些”确实执行了foreach / break会做的事情。循环直到迭代n = true。
– Antony展位
19年1月11日在16:31
声纳标记它,而不使用从array.some()返回的值。逻辑是仅将其用于循环。
–Vaisakh Rajagopal
8月7日19:46
#5 楼
不幸的是,在这种情况下,如果不使用forEach
会更好。 而不是使用常规的
for
循环,它现在将完全按照您的期望工作。 var array = [1, 2, 3];
for (var i = 0; i < array.length; i++) {
if (array[i] === 1){
break;
}
}
评论
令我震惊的是,与正确答案的更高性能,更少的代码和更好的可读性相比,最高的投票可能是最糟糕的实现。抛出异常...真的吗?传统的for循环是否还不够靠谱?
– gdbj
17-10-20在21:07
@gdbj我同意您的声明,并使用了这种方法,但真正令我震惊的是,没有这些黑客,就无法退出forEach了,现在这是一个糟糕的设计。
–斯科特
18年8月3日在18:11
@gdbj我也同意,但是问题更多的是Stack Overflow及其指南。该问题专门要求解决方案以摆脱Array.forEach循环。公认的答案以一种极其丑陋的方式做到了。从技术上讲,这个答案是错误的,即使它以尝试和真实的方式实现了相同的目标。
–尼克M
9月4日23:18
#6 楼
从您的代码示例中,您似乎正在寻找Array.prototype.find
:Array.prototype.find()和Array.prototype.findIndex()[1, 2, 3].find(function(el) {
return el === 2;
}); // returns 2
评论
这正是解决该问题的正确方法。
–丹尼尔·博切克(Daniel Boczek)
11月18日下午16:34
#7 楼
考虑使用jquery
的each
方法,因为它允许在回调函数中返回false:$.each(function(e, i) {
if (i % 2) return false;
console.log(e)
})
Lodash库还提供了可以与map / reduce链接的
takeWhile
方法/ fold等: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');
// => []
评论
使用jQuery的充分理由。仍然缺少本机javascript中的forEach。
– Alex Grande
2012年2月11日在8:46
@AlexGrande jQuery的forEach和JavaScript的forEach不兼容。
–比约恩
13年4月22日在12:56
在很多地方都不能使用JavaScript,而jQuery并不是一个选择。
– JBR威尔金森
16年5月9日在8:45
#8 楼
var array = [1,2,3,4];
for(var item of array){
console.log(item);
if(item == 2){
break;
}
}
#9 楼
如果您想使用Dean Edward的建议并抛出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子句:要记住的重要一件事是,这只会更新Array.prototype.forEach函数(如果已存在)。如果尚不存在,则不会对其进行修改。
#10 楼
简短的答案:为此使用for...break
或更改代码,以免破坏forEach
。不要使用.some()
或.every()
模拟for...break
。重写代码以避免for...break
循环,或使用for...break
。每次当您使用这些方法时,上帝就会杀死小猫。 长答案:
for...break
和.some()
都返回.every()
值,如果有任何传递函数返回的元素返回boolean
,则.some()
返回true
,如果有返回值的元素均返回true
传递的函数返回false
。这就是功能的含义。使用函数的含义并不比使用表而不是CSS差得多,因为函数会使读取代码的每个人感到沮丧。此外,将这些方法用作
false
的唯一可能方法另外一种方法是产生副作用(在for...break
回调函数之外更改一些var),这与.some()
并没有太大区别。因此,使用
for...break
或.some()
作为.every()
循环替代品并非没有道理副作用,这比for...break
干净得多,这令人沮丧,所以这不是更好。 您可以随时重写代码,从而无需在
for...break
中进行操作。您可以使用for...break
过滤数组,也可以使用.filter()
拆分数组,依此类推,然后将.slice()
或.forEach()
用于数组的那一部分。评论
实际上,使用.filter来解决很多用例是合适的解决方案。
– TKoL
15年6月8日在17:49
性能如何?如果频繁使用,过滤器不会影响性能吗?
–frascaroli
16年5月25日在13:19
是的,滤波器阵列原型可能很重。我喜欢它,但是如果使用过度,它可能会影响性能。
–乍得
19年7月16日在18:17
@tfrascaroli用于...中断循环(如果需要性能)。与.forEach()、. any()、. map()、. filter()等相比,for循环是性能最高的迭代工具。
–最大
19年7月17日在1:53
#11 楼
这只是我想出的解决问题的方法...我很确定它可以解决原始申请者所遇到的问题: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;
});
在回调函数中返回false将导致中断。让我知道这是否真的不起作用。
评论
=== false可能比== false更好,因此您不必显式返回true(或真实值)以继续循环,以免某些控制路径不返回值并且循环意外中断。
–杰克
17年4月27日在23:03
#12 楼
如前所述,您不能破坏.forEach()
。这是使用ES6迭代器进行foreach的一种更现代的方法。允许您在迭代时直接访问index
/ value
。const array = ['one', 'two', 'three'];
for (const [index, val] of array.entries()) {
console.log('item:', { index, val });
if (index === 1) {
console.log('break!');
break;
}
}
输出:
item: { index: 0, val: 'one' }
item: { index: 1, val: 'two' }
break!
链接
Array.prototype.entries()
迭代器和发电机
解构分配
#13 楼
我想到的另一个概念: function forEach(array, cb) {
var shouldBreak;
function _break() { shouldBreak = true; }
for (var i = 0, bound = array.length; i < bound; ++i) {
if (shouldBreak) { break; }
cb(array[i], i, array, _break);
}
}
// Usage
forEach(['a','b','c','d','e','f'], function (char, i, array, _break) {
console.log(i, char);
if (i === 2) { _break(); }
});
评论
语法类似于[NSArray enumerateObjectsUsingBlock],谢谢!
–Chrstph SLN
19年5月10日在15:23
@Drenai签名类似于本地Array.prototype.forEach()。在提出这个问题之前很久就存在断断续续的存在; OP正在使用功能更强大的forEach寻找该行为。
– c24w
19-10-23在10:15
@Drenai现在删除了他们的评论(但留下了反对票),其中提到,当您可以使用for ... in and break解决问题时,此解决方案的签名很难记住且不必要。
– c24w
19-10-25在9:32
#14 楼
在另一个站点上找到了此解决方案。您可以在try / catch场景中包装forEach。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 /
评论
不要将异常用作控制流语句。用它来处理意外的结果。
–最大
19年7月17日在1:54
#15 楼
如果不需要在迭代后访问数组,则可以通过将数组的长度设置为0来纾困。如果在迭代后仍然需要它,则可以使用slice对其进行克隆。.[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;
});
哪种方法比在代码中引发随机错误要好得多。
评论
做得很好:)但如果将array.length分配为0后有一些动作,它们将在当前迭代中应用,所以有时在这种分配之后最好使用return
– zhibirc
18年7月19日在13:09
#16 楼
这是一个for循环,但是像forEach()一样在循环中维护对象引用,但是您可以将其拆分。var arr = [1,2,3];
for (var i = 0, el; el = arr[i]; i++) {
if(el === 1) break;
}
#17 楼
我为此使用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
}
//
评论
为什么不扔BREAK?
–贝尔吉
15年12月17日在18:35
您可以简单地使用FOOBARED,它将引发错误。
–起搏器
6月28日12:02
#18 楼
另一种方法 var wageType = types.filter(function(element){
if(e.params.data.text == element.name){
return element;
}
});
console.dir(wageType);
评论
这是正确使用过滤器方法吗?我猜回调函数会返回一个布尔值,无论该回调函数如何,回调函数都称为数组元素,直到最后一个。
– MortezaE
6月7日7:22
#19 楼
如果您想保留forEach
语法,这是一种保持效率的方法(尽管不如常规的for循环好)。立即检查一个变量,该变量知道您是否要退出循环。 本示例使用匿名函数在
forEach
周围创建一个函数作用域,您需要存储完成的信息。 (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>
我的两分钱。
#20 楼
使用array.prototype.every
函数,该函数为您提供了打破循环的实用程序。请参阅此处的示例Mozilla开发人员网络上的Javascript文档#21 楼
同意@bobince,赞成。此外,仅供参考:
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。
#22 楼
这不是最有效的,因为您仍然循环所有元素,但是我认为可能值得考虑以下简单方法:let keepGoing = true;
things.forEach( (thing) => {
if (noMore) keepGoing = false;
if (keepGoing) {
// do things with thing
}
});
评论
continue是关键字,您的代码是语法错误。
–贝尔吉
15年12月17日在18:34
既然您仍在使用ES6,则应只切换到for for loop and break。从往常一样。
–贝尔吉
15年12月17日在18:34
固定且正确-但为了简洁起见,大多使用es6
– y夫
15年12月17日在21:53
#23 楼
您可以按照以下适用于我的代码进行操作: var loopStop = false;
YOUR_ARRAY.forEach(function loop(){
if(loopStop){ return; }
if(condition){ loopStop = true; }
});
评论
为什么是-1?它并不比捕获异常丑陋,这是一个更大的hack恕我直言。
–拜伦·惠特洛克(Byron Whitlock)
17 Mar 21 '21在21:21
#24 楼
我知道这是不正确的方法。这不是打破循环。这是一个Jugad
let result = true;
[1, 2, 3].forEach(function(el) {
if(result){
console.log(el);
if (el === 2){
result = false;
}
}
});
#25 楼
我更喜欢使用for in
var words = ['a', 'b', 'c'];
var text = '';
for (x in words) {
if (words[x] == 'b') continue;
text += words[x];
}
console.log(text);
for in
的工作原理类似于forEach
,您可以在其中添加return to exit功能。性能也更好。#26 楼
如果需要根据情况中断数组中元素的值(例如,中断条件不依赖于在分配数组元素值后可能会更改的运行时变量),也可以使用组合slice()和indexOf()的方法如下。如果在forEach到达“ Apple”时需要中断,则可以使用
var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
var fruitsToLoop = fruits.slice(0, fruits.indexOf("Apple"));
// fruitsToLoop = Banana,Orange,Lemon
fruitsToLoop.forEach(function(el) {
// no need to break
});
如W3Schools.com中所述,slice()方法将数组中选定的元素作为新的数组对象返回。原始数组将不会更改。
在JSFiddle中查看它
希望对别人有帮助。
#27 楼
尝试使用“查找”:var myCategories = [
{category: "start", name: "Start", color: "#AC193D"},
{category: "action", name: "Action", color: "#8C0095"},
{category: "exit", name: "Exit", color: "#008A00"}
];
function findCategory(category) {
return myCategories.find(function(element) {
return element.category === category;
});
}
console.log(findCategory("start"));
// output: { category: "start", name: "Start", color: "#AC193D" }
#28 楼
您可以创建forEach
的变体,以允许break
,continue
,return
甚至async
/ await
:(以TypeScript编写的示例)export type LoopControlOp = "break" | "continue" | ["return", any];
export type LoopFunc<T> = (value: T, index: number, array: T[])=>LoopControlOp;
Array.prototype.ForEach = function ForEach<T>(this: T[], func: LoopFunc<T>) {
for (let i = 0; i < this.length; i++) {
const controlOp = func(this[i], i, this);
if (controlOp == "break") break;
if (controlOp == "continue") continue;
if (controlOp instanceof Array) return controlOp[1];
}
};
// this variant lets you use async/await in the loop-func, with the loop "awaiting" for each entry
Array.prototype.ForEachAsync = async function ForEachAsync<T>(this: T[], func: LoopFunc<T>) {
for (let i = 0; i < this.length; i++) {
const controlOp = await func(this[i], i, this);
if (controlOp == "break") break;
if (controlOp == "continue") continue;
if (controlOp instanceof Array) return controlOp[1];
}
};
用法:
function GetCoffee() {
const cancelReason = peopleOnStreet.ForEach((person, index)=> {
if (index == 0) return "continue";
if (person.type == "friend") return "break";
if (person.type == "boss") return ["return", "nevermind"];
});
if (cancelReason) console.log("Coffee canceled because: " + cancelReason);
}
#29 楼
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);
#30 楼
是的,可以继续并退出forEach循环。要继续,可以使用return,循环将继续但当前函数将结束。
要退出循环,可以将第三个参数设置为0长度,设置为空数组。循环不会继续,当前函数会继续,因此您可以使用“返回”完成操作,就像在正常的for循环中退出...
此:
[1,2,3,4,5,6,7,8,9,10].forEach((a,b,c) => {
console.log(a);
if(b == 2){return;}
if(b == 4){c.length = 0;return;}
console.log("next...",b);
});
将打印以下内容:
1
next... 0
2
next... 1
3
4
next... 3
5
评论
值得注意的是,虽然return确实确实会继续迭代,但是它将跳过该块之后的所有代码。以下面的代码为例:[1,2,3] .forEach(function(el){if(el === 2){console.log(`Match on 2!`); return;} console.log(el );}); 。console.log(el);匹配2时将被跳过。