昨天講到 iteration ,今天就來講forEach()
。
其實一開始在操作陣列方法的時候,比較常使用map()
,因為一直有個印象就是forEach()
是不會改變原陣列的,但後來發現陣列的value如果是物件的話,居然可以去改變到property的值?
WHAT?
先來試試看陣列裡面都是基本型別的話會是怎樣?來直接修改value。
const array = [1,2,3,4]
array.forEach((item) => item + 1)
console.log(array)
// [1, 2, 3, 4]
跟我認知的一樣,是不會改變的。
物件型別來試試看,直接修改value的property id
const array = [
{ id:0 },
{ id:1 },
{ id:2 }
]
array.forEach(item => item.id + 1)
console.log(array)
// (3) [{…}, {…}, {…}]
// 0: {id: 0}
// 1: {id: 1}
// 2: {id: 2}
不會改變。
或者是在裡面重新賦值一個新的物件:
const array = [
{ id:0 },
{ id:1 },
{ id:2 }
]
array.forEach((item, index) => item = { xd: index })
console.log(array)
// (3) [{…}, {…}, {…}]
// 0: {id: 0}
// 1: {id: 1}
// 2: {id: 2}
OK 這些都是我認識的forEach()
,不會被改變!
BUT! 如果我只去修改物件的property並再賦值給這個property的話呢?
const array = [
{ id:0 },
{ id:1 },
{ id:2 }
]
array.forEach(item => item.id = item.id + 1)
console.log(array)
// (3) [{…}, {…}, {…}]
// 0: {id: 1}
// 1: {id: 2}
// 2: {id: 3}
唔....改到了。
那剛剛修改基本型別是直接去改他的值,如果我用index去改呢?
let array = [1, 2, 3, 4]
array.forEach((item, index) => array[index] = index)
console.log(array)
// [0, 1, 2, 3]
我的天啊竟然也改到了....
forEach()
是一個會遍歷的方法,如果在陣列裡面去直接改變value的話會有點危險,因為不確定這個陣列要變成怎樣?如果在裡面一直array.push()
,這樣豈不是變成無窮迴圈了?::危險勿試::
實測使用for...loop的確無法,我的devTools disconnect..
const array = [1,2,3,4]
for(let i = 0; i < array.length; i++) {
array.push(i)
}
但是使用forEach()
卻可以。不過很明顯的是他的確只遍歷四次,就像是forEach()
在開始跑的時候已經確定現在的長度是多少,並不會因為有增加就多跑。
const array = [1,2,3,4]
array.forEach((item) => {
array.push(item)
})
console.log(array)
// [1, 2, 3, 4, 1, 2, 3, 4]
forEach()
在進行的時候是淺拷貝一個陣列來做,所以在forEach()
的時候不會用原本的陣列,直接改變value也不是改變到原本的陣列const array = [
{ id:0 },
{ id:1 },
{ id:2 }
]
array.forEach((item, index) => item.xd = index)
console.log(array)
// (3) [{…}, {…}, {…}]
// 0: {id: 0, xd: 0}
// 1: {id: 1, xd: 1}
// 2: {id: 2, xd: 2}
真相只有一個 ------------->
就是這樣 喵
事實上當初會遇到這個問題是因為我在切to-do list的時候,使用者把資料儲存,畫面渲染資料要改變,就會直接使用forEach()
去把每個的property來換成新的資料,這些都有被改到。
tasks.forEach((task, index) => {
if (task.id === Number(id)) {
tasks[index].comment = taskComment.value;
tasks[index].title = taskTitle.value;
tasks[index].date = taskDate.value;
tasks[index].datetime = taskDatetime.value;
tasks[index].isFolded = !tasks[index].isFolded;
}
});
後來有一次想說直接用一個新的物件去賦值比較快,就直接這樣寫:
tasks.forEach((task, index) => {
if (task.id === Number(id)) {
task = {
comment: taskComment.value,
title: taskTitle.value,
date: taskDate.value,
datetime: taskDatetime.value,
isFolded: !tasks.isFolded
}
}
});
結果卻沒改到!
於是開始思考forEach()
到底有沒有辦法改到原本的陣列?理當是不行啊,那以前怎麼用都沒出事,還是一樣改到呢?
現在就知道他會如何被改變,如何不被改變,就不會突然大喊:「我以為他都是可以被改變的耶!!」,反而了然於心:「哼,我早就知道了,要怎麼對付你這傢伙!」
要改變的話就用index, key去改就好了啊!沒在怕!
今天就這樣了~明天見!
後記比結論長真的很好笑XD
參考資料:forEach 会改变原数组值吗?
foreach能否修改数据?
你还在以为forEach真的能改变原数组吗?你悟了吗?