JavaScript 引用 vs 複製
首先我們看下面這個例子:
let age = 18; let age2 = age; console.log(age, age2);
我們會得到以下的值:
這個相信大家都能很好理解。
那麼如果我們改變age
的值呢?輸出會有什麼變化?
age = 20; console.log(age, age2);
我們會得到:
看到這裡大家就奇怪了,上面的結果都很正常啊。
但在 JavaScript 中是有例外的,對於普通資料型別如 integer,string,boolean 可以通過=
來複制這個變數,但對於 array 和 object 資料型別,=
只能起到引用的效果。
大家可以看下面這個例子:
let arr = ['wes', 'bob', 'faker']; let arr2 = arr; console.log(arr2, arr); arr[2] = 'dean'; console.log(arr2, arr);
得到的結果是:
["wes", "bob", "faker"] ["wes", "bob", "faker"] ["wes", "bob", "dean"] ["wes", "bob", "dean"]
我們會發現隨著arr
的改變,arr2
也會跟著改變。
說明arr2
並沒有複製arr
的值,只是引用了它,它們都指向同一個記憶體中的值。
object 也是一樣的:
let obj = { age: 19, name: 'like', last: 'jam' }; let obj2 = obj; console.log(obj, obj2); obj.age = 50; console.log(obj, obj2);
得到的結果是:
{age: 19, name: "like", last: "jam"} {age: 19, name: "like", last: "jam"} {age: 50, name: "like", last: "jam"} {age: 50, name: "like", last: "jam"}
那麼如何複製 array 和 object 呢?
複製 array 的方法:
方法1:
let arr2 = [].concat(arr);
方法2:
let arr2 = arr.slice();
方法3:
let arr2 = Array.from(arr);
方法4:
let arr2 = [...arr];
一般我們比較常用的是方法3和方法4,方法1和方法2比較取巧,但都是可以達到複製 array 的目的的。
ps:[...arr]
是 ES6 中的方法。
複製 object 的方法:
方法1:
let obj2 = Object.assign({}, obj);
方法2:
let obj2 = {...obj};
方法1和方法2都有個缺點,它們只會複製物件的第一層。
看下面這個例子:
let obj = { number: 12, name: { first: 'bob', last: 'evil' } }; let obj2 = Object.assign({}, obj); obj.number = 50; console.log(obj, obj2);
我們會得到下面的結果:
obj = { number: 50, name: { first: 'bob', last: 'evil' } } obj2 = { number: 12, name: { first: 'bob', last: 'evil' } }
但如果我們改變第二層的值:
obj.name.first = 'sam'; console.log(obj, obj2);
obj = { number: 50, name: { first: 'sam', last: 'evil' } } obj2 = { number: 12, name: { first: 'sam', last: 'evil' } }
我們發現物件第二層依舊是引用的,並沒有實現複製。
那麼怎麼複製一個完整的 object 呢?
最簡單的方法就是使用第三方函式庫 lodash ,它提供了 clone 和 deepclone 完全可以滿足日常的需求。
object 的複製因為要考慮到很多因素,我會另開一篇,專門整理。