JavaScript 深浅拷贝
作者:Seiya
时间:2019年08月21日
浅拷贝
浅拷贝之所以被称为浅拷贝,是因为对象只会被克隆最外部的一层,至于更深层的对象,则依然是通过引用指向同一块堆内存.
function shallowCopy(obj) {
if (typeof obj !== "object") return;
var newObj = obj instanceof Array ? [] : {};
for (var key in obj) {
if(obj.hasOwnProperty(key)) {
newObj[key] = obj[key];
}
}
return newObj;
}
深拷贝
JSON.parse方法
JSON 对象 parse 方法可以将 JSON 字符串反序列化成JS对象,stringify 方法可以将 JS 对象序列化成 JSON 字符串,这两个方法结合起来就能产生一个便捷的深克隆。
const newObj = JSON.parse(JSON.stringify(oldObj));
我们举例对此方法进行测试:
const oldObj = {
a: 1,
b: [ 'e', 'f', 'g' ],
c: { h: { i: 2 } }
};
const newObj = JSON.parse(JSON.stringify(oldObj));
console.log(newObj.c.h, oldObj.c.h); // { i: 2 } { i: 2 }
console.log(oldObj.c.h === newObj.c.h); // false
newObj.c.h.i = 'change';
console.log(newObj.c.h, oldObj.c.h); // { i: 'change' } { i: 2 }
可以看出,这个方法确实能够实现深拷贝。虽然它解决绝大部分是使用场景,但是却有很多坑:
他无法实现对函数 、RegExp等特殊对象的克隆;
会抛弃对象的 constructor,所有的构造函数会指向 Object;
对象有循环引用,会报错;
构造一个深拷贝函数
一种常见的实现方式如下:
function deepCopy(obj) {
if (typeof obj !== "object") return;
var newObj = obj instanceof Array ? [] : {};
for (var key in obj) {
if(obj.hasOwnProperty(key)) {
newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
}
}
return newObj;
}
注意:
尽管使用深拷贝会完全的克隆一个新对象,不会产生副作用,但是深拷贝因为使用递归,性能会不如浅拷贝,在开发中,还是要根据实际情况进行选择。当然,最为关键的是,这个方法也会出现上面提到的问题。