前端三十|14. [JS] 深拷貝是什麼?如何實現?
Published in
7 min readSep 30, 2019
在 前天的文章 中,我們討論了 JavaScript 的資料型別,其中最特殊的莫過於物件;在這個萬物皆物件的語言中,如何完美的複製物件,也就成了開發過程中頻繁出現的功能需求;相信蠻多讀者多少也聽過深拷貝、淺拷貝這些名詞,接下來就讓我們一起瞧瞧物件拷貝的實作及背後秘辛。
本系列文已經重新編校彙整編輯成冊,並正式出版囉!
《前端三十:從 HTML 到瀏覽器渲染的前端開發者必備心法》好評販售中!
喜歡我文章內容的讀者們,歡迎您前往購買支持!
資料複製
如果我們想要複製資料,而資料型態是 JavaScript 的基本型別,那麼我們可以直接這樣寫:
let num1 = 123
let num2 = num1
num1 = 456
console.log(num2) // 123
上面的範例中,變數 num2
複製自變數 num1
,從複製之後,num1
的值便再也不會和 num2
的數值有所關聯。
那如果複製的資料是物件呢?
let obj1 = {
foo: 'bar'
}
let obj2 = obj1
obj1.foo = 'changed'
console.log(obj2.foo) // changed
這次我們宣告了變數 obj2
,複製自 obj1
,但當 obj1
內的屬性 foo
改變時,obj2
的 foo
也跟著改變了。為什麼會這樣呢?
Call by value
這是因為 JavaScript 中,物件變數所儲存的值,實際上存的是物件所在的記憶體位置:
當我們將 obj2
賦值為 obj1
時,實際上複製的只有那個記憶體位置,但記憶體位置所儲存的物件,還是同一個,也因此當物件改變時,兩個變數都會被影響。
這樣的情況該如何解決呢?這就是今天我們要來討論的問題了。
物件拷貝
最直觀的方法,就是建立一個新物件,將原本資料全部的屬性都複製進去,這樣就可以了吧?例如我們可以透過 Object.assign
,將物件全部的屬性倒過去: