[英]Splicing a Javascript array from within the callback passed to 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 循環。 如果您有更好的方法,請隨時回答。
讓我們看看為什么 JavaScript 會這樣。 根據Array.prototype.forEach
的ECMAScript 標准規范,
當您刪除索引 1 處的元素時,索引 2 處的元素將成為索引 1 處的元素,並且該對象不存在索引 2。
現在,JavaScript 在對象中查找未找到的元素 2,因此它跳過函數調用。
這就是為什么你只能看到a
和b
。
這樣做的實際方法是使用Array.prototype.filter
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' ]
一種可能性是使用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
和c
。
在 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);
});
另一種可能性是使用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
。
如果我們要刪除特定索引處的兩個元素並繼續從立即元素進行迭代,則上述所有答案都將失敗或不保留原始數組以將其傳遞到其他地方。 假設我有一個數組
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這種怪異行為的更好方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.