每个像调用断路器一样的短路数组

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

如何使用 JavaScript 中的新 forEach方法来实现这一点?我试过 return;return false;breakbreak崩溃,而 return除了继续迭代什么也不做。

1644646 次浏览

forEach中没有break的内置功能。要中断执行,您必须抛出某种类型的异常。例如。

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异常不是很漂亮。如果你真的需要break在里面,传统的for循环可能更合适。

使用#0

相反,使用#0

[1, 2, 3].some(function(el) {console.log(el);return el === 2;});

这是有效的,因为some返回true,只要任何回调以数组顺序执行,返回true,短路其余的执行。

some,它的逆#1(将在return false上停止)和forEach都是ECMAScript第五版方法,需要在缺少它们的浏览器上添加到Array.prototype中。

使用#0

[1, 2, 3].every(v => {if (v > 2) {return false // "break"}console.log(v);return true // must return true if doesn't break});

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

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

Lodash库还提供了#0方法,可以与map/duce/折叠等链接:

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');// => []

在另一个站点上找到了此解决方案。您可以在try/catch方案中包装for每个。

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/

如果您想使用爱德华院长的建议并抛出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-cat子句:

// 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.for每个函数。如果它不存在,它不会修改它。

您可以使用方法:

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

更多细节这里

这只是我想出的解决问题的方法……我很确定它解决了原始asker的问题:

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将导致中断。如果这实际上不起作用,请告诉我。

简短的回答:为此使用for...break或更改您的代码以避免破坏forEach。不要使用.some().every()来模拟for...break。重写您的代码以避免for...break循环,或使用for...break。每次您使用这些方法作为for...break替代上帝杀死小猫。

很长的回答:

.some().every()都返回boolean值,如果有任何传递函数返回true的元素,.some()返回true,如果有任何传递函数返回false的元素,每个返回false。这就是函数的意思。使用函数来实现它们不意味着的东西比使用表格来布局而不是CSS要糟糕得多,因为它会让每个阅读你代码的人感到沮丧。

此外,将这些方法用作for...break替代方案的唯一可能方法是产生副作用(在.some()回调函数之外更改一些变量),这与for...break没有太大区别。

因此,使用.some().every()作为for...break循环替代方案并不是没有副作用,这并不比for...break更干净,这令人沮丧,所以这不是更好。

您可以随时重写代码,这样就不需要for...break了。您可以使用.filter()过滤数组,您可以使用.slice()拆分数组,依此类推,然后对该部分数组使用.forEach().map()

我想出的另一个概念:

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(); }});

为此,我使用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}//

如果你不需要在迭代后访问你的数组,你可以通过将数组的长度设置为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;});

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

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);

使用array.prototype.every函数,它为您提供了打破循环的实用程序。请参阅此处的示例Mozilla开发者网络上的JavaScript留档

同意@bobince,赞成。

另外,FYI:

Prototype.js有这样的目的:

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

$break将由内部Prototype.js捕获和处理,打破“each”循环,但不产生外部错误。

详情见Prototype.JSAPI

jQuery也有办法,只需在处理程序中返回false即可提早打破循环:

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

详情见jQueryAPI

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

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

从文档:

为…在为…的语句都迭代某些东西。它们之间的主要区别在于它们迭代的内容。为…在语句按原始插入顺序迭代对象的可枚举属性。为…的语句迭代可迭代对象定义要迭代的数据。

需要迭代中的索引吗?你可以使用#0

for (const [index, el] of arr.entries()) {if ( index === 5 ) break;}

不幸的是,在这种情况下,如果你不使用forEach会好得多。相反,使用常规的for循环,它现在将完全按照您的预期工作。

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

如果你想保持你的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>

My two cents.

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

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

引用MDN留档#0

没有办法停止或打破一个forEach()循环,除了通过抛出异常。如果您需要这种行为,.forEach()方法是错误的工具,请改用普通循环。如果您正在测试谓词的数组元素并需要布尔返回值,您可以使用#1#2代替。

对于您的代码(在问题中),正如@bobince建议的那样,使用#0代替。它非常适合您的用例。

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

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

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

从你的代码示例中,看起来Array.prototype.find就是你要找的:Array.prototype.find()Array.prototype.find指数()

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

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

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

这是一个for循环,但在循环中维护对象引用,就像for每个()一样,但您可以中断。

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

如前所述,你不能打破.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!

链接

如果您需要根据数组中已经存在的元素的值来中断(例如,如果中断条件不依赖于在数组分配其元素值后可能更改的运行时变量),您也可以使用切片indexOf()索引类型的组合,如下所示。

如果你需要休息时for每个到达'苹果'你可以使用

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,切片()方法将数组中选定的元素作为新数组对象返回。原始数组不会更改。

JSFiddle中看到它

希望它能帮助某人。

尝试“查找”:

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);

您可以创建一个允许breakcontinuereturn甚至async/awaitforEach变体:(用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 entryArray.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);}

你为什么不尝试将函数包装在Promise中?

我提出它的唯一原因是我在API中使用的函数以类似的方式进行操作。我不希望它找到一个值后继续迭代,我需要返回一些东西,所以我只是要解析一个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);});

我上面的例子是在打字稿中,简单地忽略类型。希望逻辑能帮助你“打破”循环。

我使用return 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