[1,2,3].forEach(function(el) {
if(el === 1) break;
});
我如何使用JavaScript中新的forEach'方法来做到这一点?我已经试过
return;,
return false;和
break`。break "会崩溃,而 "return "除了继续迭代外什么也做不了。
在 "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 "循环可能更合适。
Array#some
。相反,使用Array#some
。
[1, 2, 3].some(function(el) {
console.log(el);
return el === 2;
});
这样做的原因是,只要任何一个按数组顺序执行的回调返回 "true","some "就会返回 "true",从而使其他回调的执行陷入短路。
some
,它的逆向every
(将在return false
时停止)和forEach
都是ECMAScript第五版的方法,需要在缺少它们的浏览器上添加Array.prototype
。
现在在ECMAScript2015(也就是ES6)中,使用新的for of loop有了更好的方法。 例如,这段代码不打印数字5之后的数组元素。
<!--开始片段。 js hide: false console: true babel: false -->
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.entry()
][1]。
for (const [index, el] of arr.entries()) {
if ( index === 5 ) break;
}
[1]: http://devdocs.io/javascript/global_objects/array/entries
您可以使用每种方法。
[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;
};
}
更多细节[这里][2].
1:
[2]: http://www.tutorialspoint.com/javascript/array_every.htm
引自Array.prototype.forEach()
](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach)的[MDN文档]。
除了没有办法停止或中断的
forEach()
循环。 抛出一个异常。 如果你需要这样的行为,.forEach()
方法是错误的工具,请使用一个普通的循环。 如果你是在测试数组元素的谓词,需要一个布尔返回值,你可以使用[every()
][1]或[some()
][2]来代替。
对于你的代码(在问题中),按照@bobince的建议,使用Array.prototype.some()
代替。
它很适合你的用例。
>.Array.prototype.some()]()
Array.prototype.some()
对数组中的每一个元素执行一次回调函数,直到找到一个回调函数返回一个真值(当转换为布尔值'时,这个值就变成真值)。 如果找到这样的元素,
some()立即返回true。 否则,
some()`返回false。
回调只对有赋值的数组索引被调用。
对于已经被删除或从未分配过值的索引不被调用。
[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every [2]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some
不幸的是,在这种情况下,如果你不使用forEach
,会好得多。
取而代之的是一个常规的for
循环,现在它将完全按照你的期望工作。
var array = [1, 2, 3];
for (var i = 0; i < array.length; i++) {
if (array[i] === 1){
break;
}
}
考虑使用jquery
'的each
方法,因为它允许在回调函数中返回错误。
$.each(function(e, i) {
if (i % 2) return false;
console.log(e)
})
Lodash库还提供了takeWhile
方法,可以与map/reduce/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');
// => []
从你的代码示例来看,你要找的是Array.prototype.find
。
[Array.prototype.find()][1]和[Array.prototype.findIndex()][2]。
[1, 2, 3].find(function(el) {
return el === 2;
}); // returns 2
[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find [2]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex
如果您想使用 [Dean Edward'的建议][1],并抛出 StopIteration 错误,以脱离循环,而不必捕捉错误,您可以使用以下函数 ([原文如此][2])。
// 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函数已经存在时,它才会更新。 如果它还不存在,它将不会修改它。
[1]: http://dean.edwards.name/weblog/2006/07/enum/#comment105309 [2]: http://gotochriswest.com/blog/2011/06/30/javascript-foreach-with-breaking/#comment-78
简短的回答。
使用 "for...break "或修改你的代码以避免 "forEach "的中断。
不要使用.some()
或.every()
来模拟for...break
。
重写你的代码以避免for...break
循环,或者使用for...break
。
每次你用这些方法作为for...break
的替代方法时,上帝就会杀死小猫。
长答案。
.some()
和.every()
都返回boolean值,
.some()如果有任何元素的传递函数返回
true,every如果有任何元素的传递函数返回
false,则返回
false`。
这就是函数的含义。
使用函数来代替它们的意思,比使用表格来代替CSS布局更糟糕,因为它让所有阅读你代码的人感到沮丧。
另外,使用这些方法作为 "for...break "替代方法的唯一可能的方法是产生副作用(在".some() "回调函数之外改变一些变量),这和 "for...break "没什么区别。
所以,使用.some()
或.every()
作为for...break
循环的替代方案并不是没有副作用的,这并不是比for...break
更干净,这是令人沮丧的,所以这并不是更好。
你可以随时重写你的代码,这样就不需要使用for...break
了。
你可以用.filter()
过滤数组,你可以用.slice()
分割数组等等,然后用.forEach()
或.map()
来处理数组的那部分。
在另一个网站上发现了这个解决方案。你可以把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; }
这是我为了解决这个问题而想出的办法......。 I'm pretty sure it fixes the problem that the original asker had:
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会导致中断。 如果这样做实际上行不通,请告诉我。
我想出的另一个概念。
<! -- 开始片段。 js hide: false console: true babel: false -->
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(); }
});
<!--结束片段-->
如果你在迭代后不需要访问你的数组,你可以通过设置数组的长度为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;
});
这是一个更好的解决方案,而不是在你的代码中随机抛出错误。
如前所述,你不能打破.forEach()
。
这里'是用ES6 Iterators做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!
我知道这不是正确的方式。 这不是破环。 它是一个Jugad <!--开始片段。 js hide: false console: true babel.false --> -- begin snippet: js hide: false console: true false -->
let result = true;
[1, 2, 3].forEach(function(el) {
if(result){
console.log(el);
if (el === 2){
result = false;
}
}
});
<!--结束片段-->
如果你想保持你的forEach
语法,这是一种保持效率的方法(虽然不如常规的for循环好)。
立即检查一个知道你是否要脱离循环的变量。
这个例子使用了一个匿名函数,用于在forEach
周围创建一个函数作用域,你需要在这个作用域中存储done信息。
<!--开始片段。 js hide.false --> -- begin snippet: js hide: false -->
(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>
<!--结束片段-->
我的两点意见。