博客 / 詳情

返回

forEach在遍歷過程中修改原數組的一些問題

我們先來看下第一段代碼:

const arr1 = [
    { id: 1, value: 1 },
    { id: 2, value: 2 },
    { id: 3, value: 3 },
    { id: 4, value: 4 },
    { id: 5, value: 5 },
]
arr1.forEach((item, index) => {
    if (item.id === 1) {
        item.value *= 10
    }
})

將第一段代碼放入瀏覽器控制枱執行完之後,打印數組arr1

[
    0: {id: 1, value: 10}
    1: {id: 2, value: 2}
    2: {id: 3, value: 3}
    3: {id: 4, value: 4}
    4: {id: 5, value: 5}
]

接着我們來看下第二段代碼:

const arr2 = [
    { id: 1, value: 1 },
    { id: 2, value: 2 },
    { id: 3, value: 3 },
    { id: 4, value: 4 },
    { id: 5, value: 5 },
]
arr2.forEach((item, index) => {
    if (item.id === 1) {
        item = { id: 6, value: 6 }
    }
})

將第二段代碼放入瀏覽器控制枱執行完之後,打印數組arr2:

[
    0: {id: 1, value: 1}
    1: {id: 2, value: 2}
    2: {id: 3, value: 3}
    3: {id: 4, value: 4}
    4: {id: 5, value: 5}
]    

我們可以發現arr2中 [id = 1] 的元素並沒有被替換成我們期望

    { id: 6, value: 6 }

當然,最後我會説怎麼在forEach遍歷過程中去替換原數組中的元素,現在我們先來討論下,為什麼會出現 [id = 1] 的元素為什麼沒有被替換掉:

要想探究原因,我們就得將上述數組用照妖鏡照一照,看看它的真面目究竟是如何

js中的數組類型,分為兩大類,
一類是值類型 數值、布爾值、null、undefined
一類是引用類型 對象、數組、函數

看下面代碼,簡單説明js字面量創建對象的過程 :

let obj = { id: 1, name: 2 }
# 虛擬機在執行到 { id: 1, name: 2 } 就會在內存中創建一個對象
# 這個對象在內存中的地址假如為 0x1110,再將此地址賦值給變量obj
# 此時obj的值實際為0x1110

理解了上述js創建過程,那麼我們來揭開arr2數組的真實面紗

# 內存地址是16進制數表示,以下地址僅為説明問題
const arr2 = [
    0x1110, 0x1111, 0x1112, 0x1113, 0x1114
]

看到arr2的真實面目,相信各位小夥伴應該明白了,上面展示的第二段代碼為什麼無效

# 那麼我們就來看看為什麼下面item沒有被替換
arr2.forEach((item, index) => {
    # 我們在遍歷的過程中,我們拿到的item值其實是
    # 0x1110, 0x1111, 0x1112, 0x1113, 0x1114 5個地址
    if (item.id === 1) {
        # { id: 6, value: 6 } 是對象的字面量創建方式,會在內存中
        # 創建一個對象,並返回對象地址 假如為 0x1115
        item = { id: 6, value: 6 }
        # 我們再將 item = { id: 6, value: 6 } 語句翻譯一下
        # 0x1110 = 0x1115
        # 看到問題了嗎?將一個16進制數賦值給另外一個16進制數
        # 其實這段是無效的賦值,也就被瀏覽器給忽略了,所以我們在
        # 打印出得結果中發現 元素{id: 1, value: 1}並沒有被
        # 替換成{id: 6, value: 6}
    }
})

可能有些初學小夥伴有疑問,既然我們在遍歷的過程中拿到的是一個內存地址,那麼在最開始第一段代碼中,為什麼又能將元素{ id: 1, value: 1 }的value值改變為10呢,那麼請給我留言,不在這裏展開這個問題。

最後總結,forEach和map遍歷中 如果想改原數組,通過下面方式就行了

arr.forEach((item, index) => {
    if (condition) {
        arr[index] = something;
    }
})

之所以會聊到這個問題,也是團隊小夥伴談到forEach遍歷過程中不能修改原數組,但是卻不知道為什麼不能修改,以及真的要修改,又如何去修改。後面想了下,可能也有其他的小夥伴有時也不太清楚,索性寫了篇小記,幫助理解。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.