需求:删除[1,2,3,4,5]中大于等于2小于5的项。(在业务场景中也是再常见不过了)
结果:[1,5]
当使用for:
let a = [1, 2, 3, 4, 5];
for (var i = 0; i < a.length; i++) {
if (a[i] >= 2 && a[i] < 5) {
a.splice(i, 1);
}
}
console.log(a);//[1,3,5]
这里没有得到正确结果,因为删除数组项时改变了数组长度,而此时索引一直在递增,那么此时索引对应的值不再是原来值了。如下:
i = 0 => a=[1,2,3,4,5]
i = 1 => 满足条件, a截取掉2,a=[1,3,4,5]
i = 2 => 此时a[2]为4了,满足条件,a截取掉4,a=[1,3,5]
此时循环已经结束,因为此时a的length为3,索引已经为2了,无法再递增。
【解决方法1】:
由于循环索引一直在递增,而数组长度却减小了,导致索引对应的值错乱了且循环次数也减少了,那么就需要手动减小索引。
let a = [1, 2, 3, 4, 5];
for (var i = 0; i < a.length; i++) {
if (a[i] >= 2 && a[i] < 5) {
a.splice(i, 1);
i--;//手动减索引,下一次循环i++ 那么就对应上了
}
}
console.log(a);//[1,5]
【解决方法2】:
既然是由于索引一直在递增,而数组长度却可能减小,导致对应不上,那么如果索引一直递减,就算数组长度减少也能正确对应上。
let a = [1, 2, 3, 4, 5];
for (var i = a.length - 1; i > 0; i--) {
if (a[i] >= 2 && a[i] < 5) {
a.splice(i, 1);
}
}
console.log(a);//[1,5]
当使用forEach:
let a = [1, 2, 3, 4, 5];
a.forEach((ele, ind) => {
if (ele >= 2 && ele < 5) {
a.splice(ind, 1);
}
})
console.log(a)//[1, 3, 5]
这里也是没有得到正确结果,原因和上面一样。
【解决方法】:
这里不能像for循环那样控制索引,因为索引是由forEach内部自己控制的。如果硬要使用forEach的话,可以保存索引,然后使用filter过滤掉。由于这里会多一次filter循环,所以还不如不使用forEach,直接使用filter过滤。
当使用filter:
这种过滤需求使用filter是最简单的了。
let a = [1, 2, 3, 4, 5];
a = a.filter(ele => {
return ele < 2 || ele >= 5;
})
console.log(a)//[1,5]
使用filter确实非常简单方便,但是很多时候我就需要使用splice方法来实现一些功能。这时候还是for循环方便了。
比如:let a = [1,2,3,4,5], b = a,c = a; 我需要改变a长度的同时也得改变b、c的长度。
如果使用filter不太方便:
let a = [1,2,3,4,5];
let b = a,c = a;
a = a.filter(ele => {
return ele < 2 || ele >= 5;
});
b = a;
c = a;//使用filter不太方便,b、c必须得重新引用a,因为filter返回的是一个全新的数组。
使用for和splice就很方便了:
let a = [1, 2, 3, 4, 5];
let b = a, c = a;
for (var i = a.length - 1; i > 0; i--) {
if (a[i] >= 2 && a[i] < 5) {
a.splice(i, 1);
}
}
console.log(a,b,c);//[1,5] [1,5] [1,5]