我有这个代码,它应该遍历数组中的每个项目,根据某些条件删除项目:
//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循环。如果你有更好的方法,请随时回答。
答案 0 :(得分:36)
让我们看看JavaScript为什么会这样。根据{{3}},
当您删除索引1处的元素时,索引2处的元素将成为索引1处的元素,而该对象的索引2不存在。
现在,JavaScript在对象中查找未找到的元素2,因此它会跳过函数调用。
这就是为什么您只看到a
和b
。
实际执行此操作的方法是使用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之后,该数组将仅包含a
和b
。
答案 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
之后,该数组将仅包含a
和c
。
答案 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这种怪异行为的更好方法。