在寫 JS 的過程中,常常會遇到需要拷貝物件或陣列的情況。
然而之後修改拷貝的內容時,發現原本的物件或陣列的屬性也跟著一起改變。
好比下面的例子:
1 | const person = { |
為什麼我修改的是 copy
的 interest,卻連 person
的值也一起改了?
這就跟 by value 與 by reference 有關了。
兩者的不同在於記憶體的位置,如果是 by value,複製時記憶體位置會是不同的,
但如果是 by reference,複製時記憶體位置會是相同的,下面就來詳細介紹與舉例。
1 | const a = 1; |
根據上面的範例,a
在記憶體中位於 0x001
位置,複製 a 的 b
在記憶體中位於 0x002
位置。
兩者位於不同的記憶體位置,所以在後續修改時,不會影響到對方。
只要是純值(數字、布林或字串),就是 by value。
1 | const a = { name: 'Blueberry' }; |
根據上面的範例,a 在記憶體中位於 0x001
位置,複製 a 的 b 在記憶體中也位於 0x001
位置。沒有新的物件產生,也沒有物件的拷貝被創造。
兩者位於相同的記憶體位置,可以說 a 其實就是 b,只是換個名字而已,所以在後續修改時,會影響到對方。
只要是物件(陣列、物件或函式),就是 by reference。
如果不希望修改時會影響到對方,就必須得使用淺拷貝或深拷貝去複製。
兩者的差異在於,淺拷貝只能複製第一層,無法深層複製第二層、第三層…等等,如果更改了第二層以後的內容,一樣會影響到原本的物件,因為第二層以後的記憶體位置與原本物件的記憶體位置還是相同的。但如果需要拷貝的物件只有一層,用淺拷貝還是可以的。
而深拷貝就不只了,它能深層複製第一層乃至最內層。不論修改的是哪一層,都不會被影響,因為它的每一層與原物件都是不同的記憶體位置。
下面就來介紹淺拷貝與深拷貝的用法。
1 | const person = { |
這裡可以看到 copy
的第二層(interest: ['閱讀', '玩遊戲']
)被修改了,結果連原本的 person
也一起變成’泡咖啡’,因為 copy
的第二層仍是指向與原物件相同的記憶體位置。
但是 name
這個值就不同了,copy
的第一層是有被淺層拷貝成功的。
for 迴圈是最土法煉鋼的方法,它也能達到淺拷貝的效果。
1 | const a = [1, 2, 3]; |
展開運算子是 ES6 新出的方法,應該是最方便的寫法了。
1 | const a = [1, 2, 3]; |
在不使用其他套件的情況下,目前 Javascript 的深拷貝只有 JSON.parse()
+ JSON.stringify()
的寫法。
1 | const person = { |
文章結束囉~如果我的文章對你有幫助,可以幫我拍個手,感謝支持!