从传递给 forEach 的回调中拼接一个 Javascript 数组

IT技术 javascript arrays foreach
2021-03-13 02:23:54

我有这段代码,它应该遍历数组中的每个项目,根据某些条件删除项目:

//iterate over all items in an array
//if the item is "b", remove it.

var array = ["a", "b", "c"];

array.forEach(function(item) {
  if(item === "b") {
    array.splice(array.indexOf(item), 1);
  }

  console.log(item);
});

期望的输出:

a
b
c

实际输出:

a
b

显然,原生 forEach 方法不会在每次迭代后检查该项目是否已被删除,因此如果是,则跳过下一个项目。除了覆盖 forEach 方法或实现我自己的类来代替数组之外,是否有更好的方法来做到这一点?

编辑 - 进一步我的评论,我想解决方案是只使用标准 for 循环。如果您有更好的方法,请随时回答。

4个回答

让我们看看为什么 JavaScript 会这样。根据ECMAScript 标准规范Array.prototype.forEach

当您删除索引 1 处的元素时,索引 2 处的元素将成为索引 1 处的元素,并且该对象不存在索引 2。

现在,JavaScript 在对象中查找未找到的元素 2,因此它跳过函数调用。

这就是为什么你只能看到ab


这样做的实际方法是使用 Array.prototype.filter

var array = ["a", "b", "c"];

array = array.filter(function(currentChar) {
    console.log(currentChar);   // a, b, c on separate lines
    return currentChar !== "b";
});
console.log(array);             // [ 'a', 'c' ]
+1 但是,如果您需要对数组项进行任何更改(就像我在我的情况下所做的那样 - 对象数组),以及过滤掉项目,最好使用reduce.
2021-04-18 02:23:54
@JuanBiscaia 这就是我的观点。在上面的例子中,返回有一个日志语句
2021-04-23 02:23:54
? return声明后,您无法将任何内容记录到控制台
2021-04-27 02:23:54
@Blauhirn 哦,好吧,对不起,我很着急,没有注意到你没有问问题,我的错。
2021-05-07 02:23:54
@Blauhirn 不,你不能。
2021-05-13 02:23:54

一种可能性是使用该array.slice(0)函数,它创建数组的副本(克隆),因此迭代与删除分离。

然后对使用的原始方法的唯一更改是array.forEach将其更改为array.slice(0).forEach,它将起作用:

array.slice(0).forEach(function(item) {
    if(item === "b") {
        array.splice(array.indexOf(item), 1);
    }
    alert(item)
});

在 forEach 之后,数组将只包含aand c

的jsfiddle演示可以在这里找到

此外,如果您使用 lodash/下划线,您可以这样做 _.clone(array).forEach(function (item) { ... })
2021-04-18 02:23:54
这很有趣,但它涉及对每次迭代的查找,尽管搜索的数组大小会减小。编写一个 for 循环并注意您的索引会更快。
2021-04-24 02:23:54

Array.prototype.filter在 thefourtheye 的回答中使用as 是一个很好的方法,但这也可以通过while循环来完成例如:

const array = ["a", "b", "c"];
let i = 0;

while (i < array.length) {
    const item = array[i];

    if (item === "b") {
        array.splice(i, 1);
    } else {
        i += 1;
    }

    console.log(item);
});

另一种可能性是使用该array.reduceRight函数来避免跳过:

//iterate over all items in an array from right to left
//if the item is "b", remove it.

const array = ["a", "b", "c"];

array.reduceRight((_, item, i) => {
    if(item === "b") {
        array.splice(i, 1);
    }

});

console.log(array);

在 之后reduceRight,数组将只包含ac