js基礎知識(6)-深淺拷貝
阿新 • • 發佈:2018-11-22
let a = {
age: 1
}
let b = a
a.age = 2
console.log(b.age) // 2
從上述例子中我們可以發現,如果給一個變數賦值一個物件,那麼兩者的值會是同一個引用,其中一方改變,另一方也會相應改變。通常在開發中我們不希望出現這樣的問題,我們可以使用淺拷貝來解決這個問題。
淺拷貝
首先可以通過 Object.assign 來解決這個問題。
let a = {
age: 1
}
let b = Object.assign({}, a)
a.age = 2
console.log(b.age) // 1
當然我們也可以通過展開運算子(…)來解決
let a = {
age: 1
}
let b = {...a}
a.age = 2
console.log(b.age) // 1
通常淺拷貝就能解決大部分問題了,但是當我們遇到如下情況就需要使用到深拷貝了
let a = {
age: 1,
jobs: {
frst: 'FE'
}
}
let b = {...a}
a.jobs.frst = 'native'
console.log(b.jobs.frst) // native
淺拷貝只解決了第一層的問題,如果接下去的值中還有物件的話,那麼就又回到剛開始的話題了,兩者享有相同的引用。要解決這個問題,我們需要引入深拷貝。
深拷貝
這個問題通常可以通過 JSON.parse(JSON.stringify(object)) 來解決。
let a = {
age: 1,
jobs: {
frst: 'FE'
}
}
let b = JSON.parse(JSON.stringify(a))
a.jobs.frst = 'native'
console.log(b.jobs.frst) // FE
但是該方法也是有侷限性的:
• 會忽略 undefined
• 不能序列化函式
• 不能解決迴圈引用的物件
let obj = { a: 1, b: { c: 2, d: 3, }, } obj.c = obj.b obj.e = obj.a obj.b.c = obj.c obj.b.d = obj.b obj.b.e = obj.b.c let newObj = JSON.parse(JSON.stringify(obj)) console.log(newObj)
如果你有這麼一個迴圈引用物件,你會發現你不能通過該方法深拷貝
在遇到函式或者 undefined 的時候,該物件也不能正常的序列化
let a = {
age: undefned,
jobs: function() {},
name: 'yck'
}
let b = JSON.parse(JSON.stringify(a))
console.log(b) // {name: "yck"}
你會發現在上述情況中,該方法會忽略掉函式和 undefined 。但是在通常情況下,複雜資料都是可以序列化的,所以這個函式可以解決大部分問題,並且該函式是內建函式中處理深拷貝效能最快的。當然如果你的資料中含有以上三種情況下,可以使用 lodash 的深拷貝函式。
如果你所需拷貝的物件含有內建型別並且不包含函式,可以使用 MessageChannel
function structuralClone(obj) {
return new Promise(resolve => {
const {port1, port2} = new MessageChannel();
port2.onmessage = ev => resolve(ev.data);
port1.postMessage(obj);
});
}
var obj = {a: 1, b: {
c: b
}}
// 注意該方法是非同步的
// 可以處理 undefined 和迴圈引用物件
const clone = await structuralClone(obj);