【问题标题】:Why does return in a node.js forEach not work as continue为什么在 node.js forEach 中返回不能继续工作
【发布时间】:2017-01-13 16:09:50
【问题描述】:

我正在尝试做与How to short circuit Array.forEach like calling break?相反的事情

arr = [{id:"231"}, {id:"343"}];
arr.forEach(function (item) {
    if (item.id === "231") {
        arr.splice(arr.indexOf(item), 1);
        return;
    }
});

基于此运行代码时,if只运行一次,如果项目顺序颠倒它运行两次,为什么?

【问题讨论】:

  • 您的代码有语法错误,无法运行。无论如何,不​​要尝试在中游修改数组。这不会有好的结局。相反,创建一个没有您不想要的项目的新数组,可能使用filter
  • 而且,.forEach() 提供了第二个参数,即index。无需使用.indexOf() 再次查找元素。
  • 更喜欢filter() 而不是splice(): var filtered = arr.filter(item => item.id !== "231")

标签: javascript node.js asynchronous


【解决方案1】:

splice 会弄乱数组的大小,并且您的循环会给出错误的结果。您应该使用filter 来执行此操作。

arr = arr.filter((item)=>{
     return item.id !== "231";
})

【讨论】:

  • 呃,.indexOf() 会在对象数组中找到一个对象就好了。
  • 当然可以,但为什么不return item.id !== 231;,或者更好的是arr.filter(item => item.id !== 231)
  • 仅供参考,"231" 是一个字符串,而不是一个数字。
  • @jfriend00 对此感到抱歉。
【解决方案2】:

改变当前数组的常用解决方案是使用for 循环并从后到前进行迭代:

var arr = [{id:"231"}, {id:"343"}];
for (var i = arr.length - 1; i >= 0; i--) {
    if (arr[i].id === "231") {
        arr.splice(i, 1);
    }
}

console.log(JSON.stringify(arr));

这样,当你splice()退出当前项时,你只是改变了你已经访问过的数组元素的索引,不影响迭代。

也可以从头到尾运行for循环,并在拼接出一个元素后纠正索引值。

var arr = [{id:"231"}, {id:"343"}];
for (var i = arr.length - 1; i >= 0; i--) {
    if (arr[i].id === "231") {
        arr.splice(i, 1);
    }
}

console.log(JSON.stringify(arr));

请记住,与 .forEach() 循环相比,普通的 for 循环始终可以让您更好地控制迭代,因为您可以随时 breakcontinue 或修改迭代索引不能用.forEach()


如果您对最终结果是一个新数组感到满意,那么 .filter() 会很容易为您工作,因为它就是为此而构建的。

var arr = [{id:"231"}, {id:"343"}];
arr = arr.filter(function(item) {
    return item.id !== "231";
});

console.log(JSON.stringify(arr));

或者,在 ES6 中:

var arr = [{id:"231"}, {id:"343"}];
arr = arr.filter(item => item.id !== "231");

console.log(JSON.stringify(arr));

【讨论】:

  • 虽然这也有效,但这是一个我不想更改太多以避免合并问题的代码段,拼接对我来说是一个更好的选择。
  • @DavidKohen - 说真的,前两个选项中的任何一个都是为了避免对数组进行不必要的复制而进行的代码更改过多?或者,如果您仍然要复制数组,请使用.filter()
  • 不,通常的解决方案是不要像这样改变数组。
  • @torazaburo - 这完全取决于您的应用程序和情况。有时复制是合适的,有时变异是合适的。每个都有非常正当的理由——这完全取决于设计和情况。理想情况下,不会通过 id 进行暴力搜索,但无论如何都会使用地图,但这些是我们在这里处理的卡片。
  • @torazaburo - 长度由数组自动调整,并在for 循环的每次迭代之前进行比较,因此它不会超出数组的末尾。如果将长度缓存在一个单独的变量中(我在这里故意不这样做),那么它也必须更新。
【解决方案3】:

拼接在 foreach 循环中使用的数组可能会导致项目跳过,为了避免这种情况,我在数组上切片的结果上运行了 forEach。

【讨论】:

  • 是的,它解决了这个问题,这就是为什么这是一个答案。
  • @AndrewLi return 不应该也不会跳过任何项目,这是导致问题的接头。
  • 如果它跳过原始数组中的项目,它不会也跳过你用 slice 制作的副本中的项目吗?
  • 不,因为循环运行在切片副本上,并且对原始文件进行了修改。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-07-06
  • 1970-01-01
  • 1970-01-01
  • 2017-11-02
  • 2011-12-07
相关资源
最近更新 更多