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

时间:2014-02-16 13:19:39

标签: javascript arrays foreach

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

//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循环。如果你有更好的方法,请随时回答。

5 个答案:

答案 0 :(得分:36)

让我们看看JavaScript为什么会这样。根据{{​​3}},

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

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

这就是为什么您只看到ab


实际执行此操作的方法是使用ECMAScript standard specification for Array.prototype.forEach

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 :(得分:13)

一种可能性是使用array.slice(0)函数,该函数创建数组的副本(clone),从而将迭代与删除分开。

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

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

在forEach之后,该数组将仅包含ab

A jsFiddle demo can be found here

答案 2 :(得分:1)

另一种可能性是使用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

答案 3 :(得分:0)

像在thefourtheye的答案中那样使用Array.prototype.filter是一个不错的方法,但是也可以通过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);
});

答案 4 :(得分:-1)

如果我们要删除特定索引处的两个元素并继续从立即元素进行迭代,则上述所有答案都将失败或不保留原始数组以将其传递到其他地方。 假设我有一个数组

vehicles = [{make: ford, model: mustang}, 
            {make: chevy, model: camaro}, 
            {make: chevy, model: camaro},
            {make: ford, model: mustang},
            {make: chevy, model: camaro}]

如果福特和雪佛兰相继出现,我想剪掉两个元素。

vehicles.forEach(function (vehicle) {
         if (vehicle) {
              var index = vehicles.indexOf(vehicle);
              var flag = vehicle.make=== "ford" && vehicles[index + 1].make=== "chevy";
              if (flag) {
                  //Array.Prototype.forEach() wouldn't update the iteration index after splice
                  vehicles.splice(index, 2, null);
              }
          }
});

因此,我用空值替换了两个拼接元素,以便适应非更新的forEach()迭代索引。然后,一旦迭代完成,我就可以清除所有插入的null的数组,并且可以随时移交该数组。

//After all the iteration is done, we clear all the inserted null
vehicles = [].concat(vehicles.filter(Boolean));

这可能是不妨碍任何事物并绝对解决javascript这种怪异行为的更好方法。