下面的函数工作得很好
function filterRangeInPlace(arr, a, b) {
for (let i = 0; i < arr.length; i++) {
let val = arr[i];
// remove if outside of the interval
if (val < a || val > b) {
arr.splice(i, 1);
i--;
}
}
}
arr=[2,3,4,5,6,7,1,0,2,12,11];
filterRangeInPlace(arr,1,5);
alert(arr);
但我想对forEach执行相同的功能
let filterRange = (arr, a, b) => {
arr.forEach((item, i) => {
val=item;debugger;
if (val < a || val > b) {
arr.splice(i, 1);
i--;
}
})
}
arr=[2,3,4,5,6,7,1,0,2,12,11];
filterRange(arr,1,5);
alert(arr);
我试过了,但没能得到正确的答案。它不能像正常迭代一样工作。有没有其他方法可以使用相同的foreach
您不能使用forEach对数组进行就地修改,因为您无法控制forEach 内部循环的索引
forEach的一个微不足道的实现就像
Array.prototype.forEach = function(cb) {
const arr = this;
for(var i = 0; i < arr.length; i++) {
cb.call(arr, arr[i], i, arr);
}
}
如果你看看上面的人,回调只是用arr[i]值调用的,如果数组发生了变异,你将无法变异内部迭代器
对于像您这样的用例,您应该使用Array.prototype.filter
let filterRange = (arr, a, b) => {
return arr.filter((item, i) => {
val=item;
if (val < a || val > b) {
return false;
}
return true;
})
}
var arr=[2,3,4,5,6,7,1,0,2,12,11];
arr = filterRange(arr,1,5);
alert(arr);
对forEach
的调用创建了在开始处理之前要处理的元素范围。
因此,当您访问i
时,您是在调用forEach
时访问该值,而不是在运行回调函数时。此外,顺便说一句,i--
在forEach
版本的算法中什么都不做,因为回调的其他实例无法访问它。
此外,如果移除一个元素,那么下一个元素将被跳过,因为这些元素将被移动到与迭代器对齐的位置。
那么,处理的是2,3,4,5,6,[skip],1,0,[skip:],12,[skip/]。这就是为什么在输出中仍然可以看到7和11。
为了获得所需的效果,你可以使用Shubham Khatri的答案,它不会改变数组,而是覆盖它。这是我会选择的方法。
然而,如果你真的想用forEach
突变数组,你需要跟踪你偏离了多远,并在前进的过程中保持正确:
let filterRange = (arr, a, b) => {
let offset = 0;
arr.forEach((item, i, inPlace) => {
if (item < a || item > b) {
inPlace.splice(i, 1);
offset++;
}
let temp_offset = offset;
while(temp_offset > 0)
{
let offset_item = inPlace[i-temp_offset];
if (offset_item < a || offset_item > b) {
inPlace.splice(i-temp_offset, 1);
offset++;
}
temp_offset--;
}
})
}
arr=[2,3,4,5,6,7,1,0,2,12,11,4,99,2];
filterRange(arr,1,5);
console.log('result',arr);
这个方法比原来的for循环更糟糕。