短路Array.forEach就像调用break

JavaScript

逆天Green古一

2020-03-09

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

如何使用forEachJavaScript中的新方法执行此操作我试过return;return false;breakbreak崩溃,return除了继续迭代外什么也不做。

第256篇《短路Array.forEach就像调用break》来自Winter(https://github.com/aiyld/aiyld.github.io)的站点

22个回答
小哥番长番长 2020.03.09

Yes it is possible to continue and to exit of a forEach loop.

To continue, you can use return, the loop will continue but the current function will end.

To exit of the loop, you can set the third parameter to 0 length, set to empty array. The loop will not continue, the current function do, so you can use "return" to finish, like exit in a normal for loop...

This:

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

will print this:

1
next... 0
2
next... 1
3
4
next... 3
5
宝儿前端 2020.03.09
var array = [1,2,3,4];

for(var item of array){
    console.log(item);
    if(item == 2){
       break;
    }
}
伽罗小哥 2020.03.09

尝试使用“查找”:

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" }
null 2020.03.09

如果需要根据情况中断数组中元素的值(例如,中断条件不依赖于在分配数组元素值后可能会更改的运行时变量),也可以使用组合的切片()的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查看

希望它能帮助某人

三千曜米亚 2020.03.09

您可以创建一个变种forEach,它允许breakcontinuereturn甚至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);
}
阳光阿飞 2020.03.09

您可以按照以下适用于我的代码进行操作:

 var     loopStop = false;
YOUR_ARRAY.forEach(function loop(){
    if(loopStop){ return; }
    if(condition){ loopStop = true; }
});
米亚小哥斯丁 2020.03.09

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

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

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

小小Stafan宝儿 2020.03.09

我知道这是不正确的方法。这不是打破循环。这是一个神态

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

泡芙古一神无 2020.03.09

为此使用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
}
//
TomDavaid 2020.03.09

另一种方法

        var wageType = types.filter(function(element){
            if(e.params.data.text == element.name){ 
                return element;
            }
        });
        console.dir(wageType);
猿阿飞Tom 2020.03.09

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

与在代码中引发随机错误相比,这是一个更好的解决方案。

十三Tony伽罗 2020.03.09

这是一个for循环,但是像forEach()一样在循环中维护对象引用,但是您可以将其拆分。

var arr = [1,2,3];
for (var i = 0, el; el = arr[i]; i++) {
    if(el === 1) break;
}
Near神乐路易 2020.03.09

这只是我想出的解决问题的方法...我很确定它可以解决原始申请者所遇到的问题:

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将导致中断。让我知道那是否实际上不起作用。

蛋蛋神乐 2020.03.09

在另一个站点上找到了此解决方案。您可以在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/

达蒙Davaid斯丁 2020.03.09

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

长答案:

.some()并且.every()都返回boolean值,.some()返回true是否有针对任何元素传递函数返回时true,每一个回报false,如果有针对任何元素传递函数返回false这就是功能的含义。使用函数的含义并不比使用表而不是CSS差得多,因为使用函数会使每个阅读您代码的人感到沮丧。

另外,使用这些方法作为for...break替代方法的唯一可能方法是产生副作用(在.some()回调函数外部更改一些var ),这与并无太大区别for...break

因此,使用.some()or .every()作为for...break循环替代品并不是没有副作用的,那么for...break,这并没有那么干净,这令人沮丧,因此还不是更好。

您始终可以重写代码,这样就不需要了for...break您可以使用筛选数组.filter(),可以使用.slice()拆分数组,然后对数组的该部分使用.forEach().map()

A达蒙 2020.03.09

从您的代码示例中,Array.prototype.find您正在寻找的是:Array.prototype.find()Array.prototype.findIndex()

[1, 2, 3].find(function(el) {
    return el === 2;
}); // returns 2
斯丁宝儿 2020.03.09

不幸的是在这种情况下,如果不使用它将更好forEach而是使用常规for循环,它现在将完全按照您的期望工作。

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

引用以下MDN文档中的内容Array.prototype.forEach()

没有办法阻止或打破一个forEach()比抛出异常等循环。如果您需要这种行为,则该.forEach()方法是错误的工具,请改用普通循环。如果要为谓词测试数组元素并且需要布尔返回值,则可以使用every()some()代替。

对于@bobince建议的代码(在问题中),请Array.prototype.some()改用。它非常适合您的用例。

Array.prototype.some()对数组中存在的每个元素执行一次回调函数,直到找到一个回调返回真值(转换为a的值)的值为止Boolean如果找到这样的元素,则some()立即返回true。否则,some()返回false。仅对具有指定值的数组索引调用回调;对于已删除或从未分配值的索引,不会调用它。

GreenGil 2020.03.09

您可以使用每种方法:

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

更多细节在这里

阳光凯 2020.03.09

现在,在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;
  }
}

从文档:

无论对于...在对...的语句迭代的东西。它们之间的主要区别在于它们迭代的内容。为...在声明中遍历对象的枚举的属性,在原来的插入顺序。对...的语句迭代数据迭代的对象定义要遍历。

迭代中需要索引吗?您可以使用Array.entries()

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

有没有内置的能力breakforEach要中断执行,您将必须抛出某种异常。例如。

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因为只要按数组顺序执行任何回调,就返回return true,从而使其余部分的执行短路。

some,它的反函数every(将在上停止return false),以及forEach所有ECMAScript Fifth Edition方法,都需要将它们添加到Array.prototype缺少它们的浏览器中。

问题类别

JavaScript Ckeditor Python Webpack TypeScript Vue.js React.js ExpressJS KoaJS CSS Node.js HTML Django 单元测试 PHP Asp.net jQuery Bootstrap IOS Android