咱們先來看下第一段代碼:數組
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] 的元素並無被替換成咱們指望code
{ id: 6, value: 6 }
固然,最後我會說怎麼在forEach遍歷過程當中去替換原數組中的元素,如今咱們先來討論下,爲何會出現 [id = 1] 的元素爲何沒有被替換掉:對象
要想探究緣由,咱們就得將上述數組用照妖鏡照一照,看看它的真面目到底是如何內存
js中的數組類型,分爲兩大類,
一類是值類型 數值、布爾值、null、undefined
一類是引用類型 對象、數組、函數虛擬機
看下面代碼,簡單說明js字面量建立對象的過程 :it
let obj = { id: 1, name: 2 } # 虛擬機在執行到 { id: 1, name: 2 } 就會在內存中建立一個對象 # 這個對象在內存中的地址假如爲 0x1110,再將此地址賦值給變量obj # 此時obj的值實際爲0x1110
理解了上述js建立過程,那麼咱們來揭開arr2數組的真實面紗io
# 內存地址是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遍歷過程當中不能修改原數組,可是殊不知道爲何不能修改,以及真的要修改,又如何去修改。後面想了下,可能也有其餘的小夥伴有時也不太清楚,索性寫了篇小記,幫助理解。