1. 程式人生 > 實用技巧 >JavaScript深拷貝淺拷貝全析

JavaScript深拷貝淺拷貝全析

淺拷貝

用淺拷貝如果改變obj2的物件,obj1不會再改變,它們不會引用一個值,但如果物件裡面還有物件,就會失效,它們是同一個引用。

方法1:用Object.create克隆物件

方法2:陣列用concat

方法3:物件用assign

方法4:擴充套件運算子(...)

方法1:用Object.create克隆物件

用法:

var obj1 = {a:2,b:{name:'小明'}};
var obj2 = Object.create(obj1);

詳解:

var obj1 = {a:2,b:{name:'小明'}};
var obj2 = Object.create(obj1);
obj2.a = 3;
obj2.b.name = '小紅';
console.log(obj1,obj2);

結果:

結論:

obj1物件中的一級物件a:2並沒有受影響,但二級物件b已經受影響。所以Object.create克隆的物件也只能實現一級物件的深拷貝

方法2:陣列用concat

用法:

[].concat(arr)

詳解:

var arr = [{id:1,name:'1',other:{sex:'男'}}]
var brr = [].concat(arr);
brr[0].id = 2;
brr[0].other.sex = '女';
console.log(arr[0],brr[0])

結果:

結論:

arr的一級物件(id)和物件裡面的物件(other.sex)都是引用同一個指標,不能實現深拷貝。

方法3:物件用assign

用法:

var obj1 = {a: 1}
var obj2 = Object.assign({}, obj1)

詳解:

var obj = {id:1,name:{a:'xx'},fn:function(){},un:undefined};
var obj2 = Object.assign({}, obj);
obj2.id = 2;
obj2.name.a = 'obj2';
console.log(obj,obj2)

結果:

結論:

obj的一級物件(id)的確不受影響,但物件裡面的物件(name.a)還是引用同一個指標,不能實現深拷貝。

方法4:擴充套件運算子(...)

用法:

var obj1 = {a: 1}
var obj2 = {...obj1}

詳解:

var obj = {id:1,name:{a:'xx'},fn:function(){},un:undefined};
var obj2 = {...obj};
obj2.id = 2;
obj2.name.a = 'obj2';
console.log(obj,obj2)

結果:

結論:

obj的一級物件(id)的確不受影響,但物件裡面的物件(name.a)還是引用同一個指標,不能實現深拷貝。

深拷貝

方法1:JSON.parse(JSON.stringify())

方法2:MessageChannel

方法3:lodash.cloneDeep

用深拷貝的話,就算物件裡面還有物件,也不會是同一個引用,但是會忽略undefinedfunction,用方法3不會忽略functionundefined

方法1:JSON.parse(JSON.stringify())

var obj1 = {a: 1}
obj2 = JSON.parse(JSON.stringify(obj1))

方法2:MessageChannel

var obj = {id:1,name:{a:'xx'}};

function structuralClone(obj) {
    return new Promise((resolve) => {
        const {port1, port2} = new MessageChannel();
        port2.onmessage = ev => resolve(ev.data);
        port1.postMessage(obj);
    })
}
structuralClone(obj).then(res=>{
    console.log(res);
    var obj3 = res;
    obj3.name.a = 'obj3';
    console.log(obj,obj3);
})

<!-- 用promise是為了好傳資料 -->

方法3:lodash.cloneDeep

import _ from 'lodash'
var obj = {id:1,name:{a:'xx'},fn:function(){},un:undefined};
var obj2 = _.cloneDeep(obj);
obj2.name.a = 'obj2';
console.log(obj,obj2)