簡體   English   中英

從傳遞給 forEach 的回調中拼接一個 Javascript 數組

[英]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.forEachECMAScript 標准規范

當您刪除索引 1 處的元素時,索引 2 處的元素將成為索引 1 處的元素,並且該對象不存在索引 2。

現在,JavaScript 在對象中查找未找到的元素 2,因此它跳過函數調用。

這就是為什么你只能看到ab


這樣做的實際方法是使用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 之后,數組將只包含ac

可以在此處找到 jsFiddle 演示

在 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 ,數組將只包含ac

如果我們要刪除特定索引處的兩個元素並繼續從立即元素進行迭代,則上述所有答案都將失敗或不保留原始數組以將其傳遞到其他地方。 假設我有一個數組

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM