跳转到内容
aswind7
GitHub
Blog

JavaScript-如何在遍历数组时操作数组元素?

介绍

这是一个比较容易踩坑的操作,你一定要谨慎。

例子

我们希望删除一个数组中大于2的数字。


最容易写出来的解法:

// demo1
var a = [4, 5, 6];

for (var i = 0; i < a.length; i++) {
	if (a[i] > 2) {
		a.splice(i, 1);
	}
}
console.log('处理之后的数组a为', a); // 处理之后的数组a为 [5]

为什么打印出来是 [5]
原因:在遍历数组的时候操作数组元素,数组会重新排列。
i为0时, length为3,数组为[4, 5, 6], 此时删除a[0] => 也就是4;
i为1时, length为2,数组为[5, 6], 此时删除a[1] => 也就是6;
i为2时, length为1,for循环不满足条件,终止。


你可以输入以下代码看看结果:

// demo2 我们将数组打印出来看看
var a = [4, 5, 6];

for (var i = 0; i < a.length; i++) {
	console.log('index为', i);
	console.log('value为', a[i]);
	if (a[i] > 2) {
		a.splice(i, 1);
	}
}

console.log('处理之后的数组a为', a); // 处理之后的数组a为 [5]

结果:

index为 0
value为 4
index为 1
value为 6
处理之后的数组a为 [5]

正确解法

解法1

// 倒序删除,不会遗漏
var a = [4, 5, 6];
for (var i = a.length - 1; i >= 0; i--) {
	if (a[i] > 2) {
		a.splice(i, 1);
	}
}

console.log('处理之后的数组a为', a); //[]

解法2

// filter函数
var a = [4, 5, 6];
var result = a.filter(function(value) {
	return value <= 2;
});

console.log('处理之后的数组a为', a); //[]

结束语

可以在浏览器中调试上面的代码看看结果。
我们在遍历数组的时候,一定要谨慎地操作 (增加、删除、修改等) 数组元素,一不小心就会踩坑。
forEach 方法也会有同样的问题:

forEach 遍历的范围在第一次调用 callback 前就会确定。调用forEach 后添加到数组中的项不会被 callback 访问到。如果已经存在的值被改变,则传递给 callback 的值是 forEach 遍历到他们那一刻的值。已删除的项不会被遍历到。如果已访问的元素在迭代时被删除了(例如使用 shift()) ,之后的元素将被跳过 - 参见下面的示例。
引自 mdn