JS手写深拷贝
深拷贝:假设我有一个对象A,我赋值给B,无论怎么改变B,A都不会发生任何的改变,即为深拷贝
浅拷贝:假设我有一个嵌套对象A,我赋值给B,改变一下B里面的嵌套对象,A会跟着改变,而改变一下第一层的属性A却不改变,即为浅拷贝。
网上有很多说数组的slice、concat方法对数组使用,或者对象使用Object.assign()和ES6的扩展运算符(…)可以实现深拷贝,这是不对的,以上的方法只能对一层的对象有用,多层嵌套的是不起作用的,什么是多层嵌套,下面是两层,obj对象属性name也是一个对象,还可以无限嵌套,以上的方法对下面的多层嵌套是没用的。
var obj = {
age: 13,
name: {
addr: ‘天边’
}
}
下面两种方法实现了深拷贝,不管你是一层还是多层对象。
第一种:脑残法
function deepClone(obj) {
if(typeof obj != 'object') return obj;
return JSON.parse(JSON.stringify(obj))
}
// 测试
var obj = {
name: 123
}
var obj1 = obj;
obj1.name = 345;
console.log(obj.name); // 345 这里看到 我们把obj赋值给obj1 然后修改obj1的name值,obj的name值同样发生了改变
var obj2 = deepClone(obj);
obj2.name = 678
console.log(obj.name); //345 把obj赋值给obj2 然后修改obj2的name值 obj的值不发生改变
上面的脑残法简单粗暴,但是有一个缺陷:
function deepClone(obj) {
if (typeof obj != 'object') return obj;
return JSON.parse(JSON.stringify(obj))
}
// 测试
var obj = {
name: 123
}
obj.test = obj
var obj1 = obj;
var obj2 = deepClone(obj);
如果有对自身的引用,obj有一个属性名叫test,他的值就是obj本身,这个时候就报错了,报错如下,说明使用的JSON.parse(JSON.stringify(obj))的前提是对象不能有对自身的引用
第二种:递归法
function deepClone(obj) {
if (typeof obj != 'object') return obj;
var temp = Array.isArray(obj) ? [] : {
};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
if (obj[key] && typeof obj[key] == 'object') {
// 如果obj[key]还是对象则执行递归
temp[key] = deepClone(obj[key]); // 递归
} else {
temp[key] = obj[key];
}
}
}
return temp;
}
var obj = {
age: 13,
name: {
addr: '天边'
}
}
var obj2 = deepClone(obj);
obj2.age = 14
obj2.name.addr = '地心'
console.log(obj.age); //13
console.log(obj.name.addr); //天边