打破数组循环函数(map、forEach 等)的循环
Break the loop of an Array looping function (map, forEach, etc.)
如何从数组的隐式循环中中断(类似于 break
语句)?
Array.prototype.map
、Array.prototype.forEach
等函数暗示对数组元素的循环。我想有条件地提前打破这个循环。
这个人为的例子:
const colours = ["red", "orange", "yellow", "green", "blue", "violet"];
colours.map(item => {
if (item.startsWith("y")) {
console.log("The yessiest colour!");
break;
}
});
导致 SyntaxError: Illegal break statement
.
我怎样才能像 break
语句那样打破循环?
尽管 forEach
被设计为 运行 一些 不会 改变数组的功能(即它被设计为做一些其他的副作用每个项目),它被明确记录为无法打破循环。
来自MDN documentation for forEach
:
There is no way to stop or break a forEach()
loop other than by throwing an exception. If you need such behavior, the forEach()
method is the wrong tool.
因此,尽管 forEach
是为副作用而设计的,但无法正常访问循环的控制结构。
因为 Array.prototype.map
和 Array.prototype.reduce
旨在生成一个新值,所以它们不是为早期中断等副作用而设计的。文档似乎没有明确说明这一点。
尝试的可能替代方法:重新编写代码以使用 Array.prototype.some
or Array.prototype.every
。当它们的条件已知时(当 some
将 return true
,或当 every
将 return false
).
colours.prototype.some(item => {
if (item.startswith("y")) {
console.log("The yessiest colour!");
return true;
}
});
你不能用常规的方法来做。您可以通过记住循环是否为 "broken" 来模拟 break
行为。缺少此解决方案的是循环实际上仍在继续(尽管跳过了迭代逻辑)。
let isBroken = false;
colours.map(item => {
if (isBroken) {
return;
}
if (item.startsWith("y")) {
console.log("The yessiest colour!");
isBroken = true;
return;
}
});
您的示例的最佳解决方案是使用普通 for
循环。
for (colour of colours) {
if (colour.startsWith("y")) {
console.log("The yessiest colour!");
break;
}
}
您也可以使用一种肮脏的方式来真正停止 map
循环。
colours.map((item, index, array) => {
if (item.startsWith("y")) {
console.log("The yessiest colour!");
array.splice(0, index);
}
});
// The colours array will be modified after this loop
如果您唯一的选择是使用 Array.forEach
,您可以抛出异常
参考这个:
How to short circuit Array.forEach like calling break?
还有其他可用的方法也可以解决您的问题。例如,你可以使用方法:Array.prototype.some() 如果你想检查某些条件并根据该条件打破循环。
例子可以参考这里:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some
Array#map
、Array#forEach
等从未被设计为停止。这会让人感到奇怪,因为 map
和 forEach
的意图实际上是遍历所有项目。
此外,我认为不可能通知调用者发生了 break
事件,因为它在函数中,而不是原始循环的组成部分。
所以让我们看看在第一次出现 true
时停止循环而没有 return 匹配值本身的自定义方法:
Object.defineProperty(Array.prototype, 'untilTrue', {
enumerable: false,
value: function(lambda) {
for(let i in this) {
if(lambda.call(this, this[i])) return;
}
}
});
const colours = ["red", "orange", "yellow", "green", "blue", "violet"];
colours.untilTrue(item => {
if (item.startsWith("y")) {
console.log("The yessiest colour!");
return true;
}
console.log(item);
});
比较此习俗 untilTrue
与 Array#find
的使用:
const colours = ["red", "orange", "yellow", "green", "blue", "violet"];
colours.find(item => {
if (item.startsWith("y")) {
console.log("The yessiest colour!");
return true;
}
return false;
});
唯一值得注意的区别是 untilTrue
没有 return 匹配项 - Array#find
除了调用 lambda
.
所以一般来说,我会坚持使用 Array#find
以保持代码整洁干净,并像这样使用它:
const colours = ["red", "orange", "yellow", "green", "blue", "violet"];
if(colours.find(item => item.startsWith("y")) !== undefined) {
console.log("The yessiest colour!");
}
这会在第一个匹配项(和 returns 匹配元素)处停止循环。另请注意,您必须与 undefined
进行比较 - 如果您正在搜索 false
或 null
值,则如果仅与 true
.
您可以通过这些方式创建自定义的 forEach 方法
Array.prototype._forEach = function (callback) {
let _break = false;
const breaker = () => {
_break = true;
};
for (let index = 0; index < this.length; index++) {
if (_break) break;
callback(this[index], index, breaker);
}
};
// Example for usage:
const letters = ["a", "b", "c", "d", "e", "f", "g"];
letters._forEach((data, index, breaker) => {
if (data === "c") return; // continue role
if (data === "e") return breaker(); // break role
console.log(`log ${index}: ${data}`);
});
/**
* result:
* log 0: a
* log 1: b
* log 3: d
*/
或者您可以通过创建
来创建顶级自定义 forEach 方法
function forEach(items, callback) {
let _break = false;
const breaker = () => {
_break = true;
};
for (let index = 0; index < items.length; index++) {
if (_break) break;
callback(items[index], index, breaker);
}
}
如何从数组的隐式循环中中断(类似于 break
语句)?
Array.prototype.map
、Array.prototype.forEach
等函数暗示对数组元素的循环。我想有条件地提前打破这个循环。
这个人为的例子:
const colours = ["red", "orange", "yellow", "green", "blue", "violet"];
colours.map(item => {
if (item.startsWith("y")) {
console.log("The yessiest colour!");
break;
}
});
导致 SyntaxError: Illegal break statement
.
我怎样才能像 break
语句那样打破循环?
尽管 forEach
被设计为 运行 一些 不会 改变数组的功能(即它被设计为做一些其他的副作用每个项目),它被明确记录为无法打破循环。
来自MDN documentation for forEach
:
There is no way to stop or break a
forEach()
loop other than by throwing an exception. If you need such behavior, theforEach()
method is the wrong tool.
因此,尽管 forEach
是为副作用而设计的,但无法正常访问循环的控制结构。
因为 Array.prototype.map
和 Array.prototype.reduce
旨在生成一个新值,所以它们不是为早期中断等副作用而设计的。文档似乎没有明确说明这一点。
尝试的可能替代方法:重新编写代码以使用 Array.prototype.some
or Array.prototype.every
。当它们的条件已知时(当 some
将 return true
,或当 every
将 return false
).
colours.prototype.some(item => {
if (item.startswith("y")) {
console.log("The yessiest colour!");
return true;
}
});
你不能用常规的方法来做。您可以通过记住循环是否为 "broken" 来模拟 break
行为。缺少此解决方案的是循环实际上仍在继续(尽管跳过了迭代逻辑)。
let isBroken = false;
colours.map(item => {
if (isBroken) {
return;
}
if (item.startsWith("y")) {
console.log("The yessiest colour!");
isBroken = true;
return;
}
});
您的示例的最佳解决方案是使用普通 for
循环。
for (colour of colours) {
if (colour.startsWith("y")) {
console.log("The yessiest colour!");
break;
}
}
您也可以使用一种肮脏的方式来真正停止 map
循环。
colours.map((item, index, array) => {
if (item.startsWith("y")) {
console.log("The yessiest colour!");
array.splice(0, index);
}
});
// The colours array will be modified after this loop
如果您唯一的选择是使用 Array.forEach
,您可以抛出异常参考这个:
How to short circuit Array.forEach like calling break?
还有其他可用的方法也可以解决您的问题。例如,你可以使用方法:Array.prototype.some() 如果你想检查某些条件并根据该条件打破循环。
例子可以参考这里:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some
Array#map
、Array#forEach
等从未被设计为停止。这会让人感到奇怪,因为 map
和 forEach
的意图实际上是遍历所有项目。
此外,我认为不可能通知调用者发生了 break
事件,因为它在函数中,而不是原始循环的组成部分。
所以让我们看看在第一次出现 true
时停止循环而没有 return 匹配值本身的自定义方法:
Object.defineProperty(Array.prototype, 'untilTrue', {
enumerable: false,
value: function(lambda) {
for(let i in this) {
if(lambda.call(this, this[i])) return;
}
}
});
const colours = ["red", "orange", "yellow", "green", "blue", "violet"];
colours.untilTrue(item => {
if (item.startsWith("y")) {
console.log("The yessiest colour!");
return true;
}
console.log(item);
});
比较此习俗 untilTrue
与 Array#find
的使用:
const colours = ["red", "orange", "yellow", "green", "blue", "violet"];
colours.find(item => {
if (item.startsWith("y")) {
console.log("The yessiest colour!");
return true;
}
return false;
});
唯一值得注意的区别是 untilTrue
没有 return 匹配项 - Array#find
除了调用 lambda
.
所以一般来说,我会坚持使用 Array#find
以保持代码整洁干净,并像这样使用它:
const colours = ["red", "orange", "yellow", "green", "blue", "violet"];
if(colours.find(item => item.startsWith("y")) !== undefined) {
console.log("The yessiest colour!");
}
这会在第一个匹配项(和 returns 匹配元素)处停止循环。另请注意,您必须与 undefined
进行比较 - 如果您正在搜索 false
或 null
值,则如果仅与 true
.
您可以通过这些方式创建自定义的 forEach 方法
Array.prototype._forEach = function (callback) {
let _break = false;
const breaker = () => {
_break = true;
};
for (let index = 0; index < this.length; index++) {
if (_break) break;
callback(this[index], index, breaker);
}
};
// Example for usage:
const letters = ["a", "b", "c", "d", "e", "f", "g"];
letters._forEach((data, index, breaker) => {
if (data === "c") return; // continue role
if (data === "e") return breaker(); // break role
console.log(`log ${index}: ${data}`);
});
/**
* result:
* log 0: a
* log 1: b
* log 3: d
*/
或者您可以通过创建
来创建顶级自定义 forEach 方法function forEach(items, callback) {
let _break = false;
const breaker = () => {
_break = true;
};
for (let index = 0; index < items.length; index++) {
if (_break) break;
callback(items[index], index, breaker);
}
}