[JS30筆記]-Day14 Object and Arrays — Reference VS Copy
今天要學習 JS 中「傳值」或「傳址」的觀念,以及淺層複製、深層複製的方法。
學習重點
一、字串、數字、布林 皆為傳值
二、陣列傳址
三、陣列淺層複製的 4 種方法
.slice()
[].concat()
[… ]
展開運算符Array.from()
四、物件傳址
五、物件淺層複製的 2 種方法
Object.assign({}, , )
{...}
展開運算符
六、物件深層複製 — JSON.parse(JSON.stringify())
一、字串、數字、布林 皆為傳值
以上範例中,age2 只是將 age 的內容複製一份過來,此時兩者是各自獨立的,就算去改變其中一個變數的值,也不影響另一個。此種傳遞資料的概念即為「傳值」。
除了以上的數字傳值範例,字串和布林也是透過「傳值」的方式,將內容複製到另一個變數,複製後就互不影響。
二、陣列傳址
players 為一個陣列,此時若讓 team = players,在 JavaScript 中是透過「引用」的方式傳遞資料,會讓兩個變數都指向同一個實體,此種傳遞資料的概念即為「傳址」。
所以當我們修改 team 陣列內的其中一個項目,players 陣列也會跟著改變。
三、陣列淺層複製的 4 種方法
如果不希望修改陣列的一個項目後,會和另一個陣列互相連動,可以使用淺層複製的方式,將陣列複製成另一個新陣列。分別有以下 4 種方法 :
.slice()
const team2 = players.slice();
2. [].concat()
const team2 = [].concat(players);
3. [… ]
展開運算符
const team2 = [...players];
4. Array.from()
const team2 = Array.from();
四、物件傳址
物件和陣列一樣,也是以「傳址」的方式在傳遞資料。
所以如以上範例中,用 person2 = person 複製一份的這種做法,一樣會有兩物件互相連動的問題。
五、物件淺層複製的 2種方法
Object.assign({},)
複製一個物件 :
const person2 = Object.assign({}, person);
複製並改變物件內其中一個項目值 :
const person2 = Object.assign({}, person, {name: 'Wesley'});
2. {...}
展開運算符
const person2 = {...person}
以上兩種方法雖能將物件複製成另一個新物件,但當物件有第二層,修改淺層複製過後的第二層內容,依然會影響原物件
以上範例中,修改物件內 name 屬性的值,並不會影響另一個物件。但當我們修改物件內, social 物件裡的 twitter 值,另一個物件內的 twitter 值也會跟著改變。
六、物件深層複製 — JSON.
parse(JSON.stringify())
如果想避免複製物件後,修改第二層的內容仍會與原物件連動,我們可以使用深層複製的方法。
但影片中有提到,不太推薦這種作法,使用前可以先思考看看是否有其必要性,因為一般很少有需要深層複製一整個物件的情況。
深層複製的方法,可以參考 lodash 函示庫內,已有的深層複製函式來幫助我們。
或是使用以下方法,先將物件用 JSON.stringify
轉為 JSON 字串,再用 JSON.parse
轉回原型別 — 物件,來做深層複製 :
const person3 = JSON.parse(JSON.stringify(person));