[1,2,3].forEach(function(el) {
if(el === 1) break;
});
如何使用 JavaScript 中的新 forEach
方法执行此操作?我试过 return;
、return false;
和 break
。 break
崩溃,return
只继续迭代。
return
确实继续迭代,但它会跳过块中它之后的任何代码。以这段代码为例: [1,2,3].forEach(function(el) { if(el === 2) { console.log(`Match on 2!`); return; } console.log(el); });
。匹配 2 时将跳过 console.log(el);
。
forEach
中没有内置的 break
功能。要中断执行,您必须抛出某种异常。例如。
var BreakException = {};尝试 { [1, 2, 3].forEach(function(el) { console.log(el); if (el === 2) throw BreakException; }); } catch (e) { if (e !== BreakException) throw e; }
JavaScript 异常并不是非常漂亮。如果您确实需要在其中使用 break
,则传统的 for
循环可能更合适。
使用数组#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
中。
现在,在 ECMAScript2015(又名 ES6)中使用新的 for of loop 有更好的方法来执行此操作。例如,此代码不打印数字 5 之后的数组元素:
让 arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; for (let el of arr) { console.log(el); if (el === 5) { 休息; } }
从文档:
for...in 和 for...of 语句都会迭代某些内容。它们之间的主要区别在于它们迭代的内容。 for...in 语句以原始插入顺序迭代对象的可枚举属性。 for...of 语句迭代可迭代对象定义要迭代的数据。
迭代中需要索引吗?您可以使用 Array.entries()
:
for (const [index, el] of arr.entries()) {
if ( index === 5 ) break;
}
entries
。 for (const [index, element] of someArray.entries()) { // ... }
Object.entries(myObject)
,然后像使用数组的 for..in
一样使用它。请注意,JS 数组基本上是底层对象:blog.niftysnippets.org/2011/01/myth-of-arrays.html
您可以使用 every 方法:
[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;
};
}
更多详情here。
[1,2,3].every( el => el !== 1 )
every
保证调用是按顺序进行的吗?
k
从0开始并递增1的算法:http://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.every
引用 MDN documentation of Array.prototype.forEach()
:
除了抛出异常之外,没有其他方法可以停止或中断 forEach() 循环。如果您需要这种行为,则 .forEach() 方法是错误的工具,请改用普通循环。如果您正在测试谓词的数组元素并且需要布尔返回值,则可以使用 every() 或 some() 代替。
根据@bobince 的建议,对于您的代码(在问题中),请改用 Array.prototype.some()
。它非常适合您的用例。
Array.prototype.some() 对数组中存在的每个元素执行一次回调函数,直到找到一个回调函数返回一个真值(当转换为布尔值时变为真值)。如果找到这样的元素, some() 立即返回 true。否则, some() 返回 false。回调仅针对已分配值的数组索引调用;对于已被删除或从未被赋值的索引,它不会被调用。
不幸的是,在这种情况下,如果您不使用 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
考虑使用 jquery
的 each
方法,因为它允许在回调函数中返回 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's suggestion 并抛出 StopIteration 错误以跳出循环而不必捕获错误,则可以使用以下函数 (originally from here):
// 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.forEach 函数已经存在,它只会更新它。如果它不存在,它不会修改它。
简短的回答:为此使用 for...break
或更改您的代码以避免破坏 forEach
。不要使用 .some()
或 .every()
来模拟 for...break
。重写代码以避免 for...break
循环,或使用 for...break
。每次您将这些方法用作for...break
替代方法时,上帝都会杀死小猫。
长答案:
.some()
和 .every()
都返回 boolean
值,如果传递函数返回 true
的任何元素,则 .some()
返回 true
,如果传递函数返回 {7 的任何元素,则每个返回 false
}。这就是函数的含义。使用没有意义的函数比使用表格而不是 CSS 更糟糕,因为它让阅读您的代码的每个人都感到沮丧。
此外,将这些方法用作 for...break
替代方法的唯一可能方法是产生副作用(在 .some()
回调函数之外更改一些变量),这与 for...break
没有太大区别。
因此,使用 .some()
或 .every()
作为 for...break
循环替代方案并非没有副作用,这并不比 for...break
更干净,这令人沮丧,所以这并不是更好。
您可以随时重写您的代码,以便在 for...break
中不需要。您可以使用 .filter()
过滤数组,您可以使用 .slice()
拆分数组等等,然后使用 .forEach()
或 .map()
作为数组的那一部分。
for...break
循环。 for
循环是比 .forEach()
、.any()
、.map()
、.filter()
等性能最高的迭代工具。
如前所述,您不能破坏 .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()
迭代器和生成器
解构赋值
我提出的另一个概念:
函数 forEach(array, cb) { var shouldBreak;函数 _break() { shouldBreak = true; } for (var i = 0, bound = array.length; i < bound; ++i) { if (shouldBreak) { break; } cb(数组[i],我,数组,_break); } } // 用法 forEach(['a','b','c','d','e','f'], function (char, i, array, _break) { console.log(i, char); if (i === 2) { _break(); } });
Array.prototype.forEach()
。 for
和 break
早在问这个问题之前就已经存在了; OP 正在使用功能更强大的 forEach
来寻找该行为。
for...in
和 break
解决问题时,此解决方案的签名很难记住且不必要。
这只是我想出的解决问题的方法......我很确定它解决了原始提问者遇到的问题:
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(或真值)来继续循环,以免某些控制路径不返回值并且循环意外中断。
如果您不需要在迭代后访问您的数组,您可以通过将数组的长度设置为 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
可能会更好
在另一个网站上找到了这个解决方案。您可以将 forEach 包装在 try / catch 场景中。
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/
这是一个 for 循环,但像 forEach() 一样在循环中维护对象引用,但您可以中断。
var arr = [1,2,3];
for (var i = 0, el; el = arr[i]; i++) {
if(el === 1) break;
}
尝试“查找”:
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" }
还有一种方法:
var wageType = types.filter(function(element){
if(e.params.data.text == element.name){
return element;
}
});
console.dir(wageType);
我为此目的使用 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
}
//
throw BREAK
?
FOOBARED
,它会引发错误。
使用 array.prototype.every
函数,它为您提供中断循环的实用程序。在此处查看示例 Javascript documentation on Mozilla developer network
同意@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。
如果您想保留 forEach
语法,这是一种保持其效率的方法(尽管不如常规 for 循环好)。立即检查知道是否要跳出循环的变量。
此示例使用匿名函数围绕您需要存储 done 信息的 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; } }); })();
我的两分钱。
如果您需要根据您的情况下已经在数组中的元素的值进行中断(即,如果中断条件不依赖于在数组被分配其元素值后可能发生变化的运行时变量),您也可以使用组合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
});
如 in W3Schools.com 所述, slice() 方法将数组中的选定元素作为新数组对象返回。原始数组不会改变。
在 JSFiddle 中查看
希望它可以帮助某人。
为什么不尝试将函数包装在 Promise 中?
我提出它的唯一原因是我在 API 中使用了一个与 forEach 类似的函数。我不希望它在找到值后继续迭代,我需要返回一些东西,所以我只是要解决一个 Promise 并这样做。
traverseTree(doc): Promise<any> {
return new Promise<any>((resolve, reject) => {
this.gridOptions.api.forEachNode((node, index) => {
//the above function is the one I want to short circuit.
if(node.data.id === doc.id) {
return resolve(node);
}
});
});
}
然后你需要做的就是对结果做一些事情,比如
this.traverseTree(doc).then((result) => {
this.doSomething(result);
});
我上面的例子是打字稿,只需忽略类型。逻辑应该有希望帮助你“打破”你的循环。
这不是最有效的,因为您仍然循环所有元素,但我认为可能值得考虑非常简单:
let keepGoing = true;
things.forEach( (thing) => {
if (noMore) keepGoing = false;
if (keepGoing) {
// do things with thing
}
});
continue
是关键字,您的代码是语法错误。
for of
循环和 break;
。
您可以按照以下对我有用的代码:
var loopStop = false;
YOUR_ARRAY.forEach(function loop(){
if(loopStop){ return; }
if(condition){ loopStop = true; }
});
我知道这不是正确的方式。它不是打破循环。这是一个朱加德
让结果=真; [1, 2, 3].forEach(function(el) { if(result){ console.log(el); if (el === 2){ result = false; } } });
在 React 中突破内置的 Array.prototype.map 函数 esp
这里要注意的关键是使用语句 return
来 BREAK
let isBroken = false;
colours.map(item => {
if (isBroken) {
return;
}
if (item.startsWith("y")) {
console.log("The yessiest colour!");
isBroken = true;
return;
}
});
更多信息在这里:https://www.codegrepper.com/code-examples/javascript/break+out+of+map+javascript
您可以创建允许 break
、continue
、return
甚至 async
/await
的 forEach
变体:(用 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);
}
ForEach
函数中处理(它不是通用 forEach
函数)——调用者不需要读取 Array 原型上的任何内容。也就是说,我实际上并没有在生产代码中使用上述解决方案——它只是展示了如何在类似 forEach
的函数中完成这些不同的运算符,如果他们愿意的话。
我使用 return false
,它对我有用。
const Book = {"Titles":[
{"Book3" : "BULLETIN 3"},
{"Book1" : "BULLETIN 1"},
{"Book2" : "BULLETIN 2"}
]}
const findbystr = function(str) {
Book.Titles.forEach(function(data) {
if (typeof data[str] != 'undefined') {
return data[str];
}
}, str)
}
book = findbystr('Book1');
console.log(book);
some
和every
,这应该在答案中排在首位。无法理解为什么人们认为它的可读性较低。真是太棒了!Array#some
的使用非常好。首先它与大多数浏览器兼容,包括 ie9 和 firefox 1.5 也非常好用。我的示例用例是在范围[a,b] 数组中查找索引,其中一个数字位于下边界和上边界对之间,测试并在找到时返回 true。for..of
将是下一个最佳解决方案,但仅适用于较新的浏览器。forever
。所有其他循环构造都由forever
和适当的可迭代异常组成,例如ContinueIteration
和StopIteration
(其中break
是要引发的宏)。一方面:从不。另一方面:总是。在紧握的手上:有时?您评论中的“PERIOD”暗示可能有引用来支持您的建议?