一、理解
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
二、浅拷贝与深拷贝
浅拷贝:赋值时,基本数据类型按值传递,对象按引用传递
var a = 25;
var b = a;
b = 18;
console.log(a);//25
console.log(b);//18
// b 的修改并不会影响到 a,因为它们是基本类型数据
var obj1 = {a: 10, b: 20, c: 30};
var obj2 = obj1;
obj2.b = 100;
console.log(obj1);
// {a: 10, b: 100, c: 30} <– b 被改到了
console.log(obj2);
// {a: 10, b: 100, c: 30}
// obj2 修改了 b 的值,同时 obj1 的 b 也会被修改,因为他们根本是同一个对象,这就是所谓的浅拷贝
深拷贝:
var obj1 = {a: 10, b: 20, c: 30};
var obj2 = {a: obj1.a, b: obj1.b, c: obj1.c};
obj2.b = 100;
console.log(obj1);
// {a: 10, b: 20, c: 30} <– b 沒被改到
console.log(obj2);
// {a: 10, b: 100, c: 30}
三、实现方式
浅拷贝的实现方式(1)直接赋值,就是浅拷贝。对象直接复制,则新对象的改变也会修改到旧对象。(2)Object.assign(target, …sources)
Object.assign 是 ES6 的新函数。Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign() 进行的是浅拷贝,拷贝的是属性值。假如源对象的属性值是一个指向对象的引用,它也只拷贝那个引用值。
var obj = {a: {a: “hello”, b: 21} };
var initalObj = Object.assign({}, obj);
initalObj.a.a = “changed”;
console.log(obj.a.a); // “changed”
(3)对象展开符 …
var obj = [{index: 1, msg: ‘one’}, {index: 2, msg: ‘two’}];
var obj2 = […obj];
console.log(obj2); //[{index: 1, msg: ‘one’}, {index: 2, msg: ‘two’}]
obj2.push({index: 3, msg: ‘three’});
console.log(obj2); // [{index: 1, msg: ‘one’}, {index: 2, msg: ‘two’}, {index: 3, msg: ‘three’}]
console.log(obj); // [{index: 1, msg: ‘one’}, {index: 2, msg: ‘two’}]
obj2[1].msg = ‘two again’;
console.log(obj2); // [{index: 1, msg: ‘one’}, {index: 2, msg: ‘two again’}, {index: 3, msg: ‘three’}]
console.log(obj); // [{index: 1, msg: ‘one’}, {index: 2, msg: ‘two again’}]
深拷贝的实现方式(1)手动复制
var obj1 = {a: 10, b: 20, c: 30};
var obj2 = {a: obj1.a, b: obj1.b, c: obj1.c};
(2)转成 JSON 再转回来(只有可以转成 JSON 格式的对象才可以这样用,像 function 没办法转成 JSON)
var obj1 = {body: { a: 10} };
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.body.a = 20;
console.log(obj1);
// {body: { a: 10} } <– 沒被改到
console.log(obj2);
// {body: { a: 20} }
console.log(obj1 === obj2);
// false
console.log(obj1.body === obj2.body);
// false
(3)使用 var newObj = Object.create(oldObj) 方法
function deepClone(initalObj, finalObj) {
var obj = finalObj || {};
for (var i in initalObj) {
var prop = initalObj[i]; // 避免相互引用对象导致死循环,如 initalObj.a = initalObj 的情况
if(prop === obj) {
continue;
}
if (typeof prop === ‘object’) {
obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
} else {
obj[i] = prop;
}
}
return obj;
}
var str = {};
var obj = {a: {a: “hello”, b: 21} };
deepClone(obj, str);
四、参考
【1】关于 JavaScript 的浅拷贝和深拷贝