看一段代码
let obj = {
name: '张三',
child: {
age: 23
}
}
let obj2 = obj;
console.log(obj); //{'张三'}
obj2.name = "李四";
console.log(obj); //{'李四'}
那我把它的值复制不就行了吗,再来一段代码
let obj = {
name: '张三',
child: {
age: 23
}
}
let obj2 = {};
Object.keys(obj).forEach(key => {
obj2[key] = obj[key];
})
obj2.name = '李四'
obj2.child.age = 21;
console.log(obj); // 张三 21
你会发现子对象修改源对象也进行了修改
这就是浅拷贝本质。在深一点的本质就是栈与堆内存的使用。
优化一下:
function shadowClone(sourceObj) {
let targetObj = Array.isArray(sourceObj) ? [] : {}; //数组还是对象
Object.keys(sourceObj).forEach(key => {
targetObj[key] = sourceObj[key];
})
return targetObj;
}
那我递归把子对象值也复制一遍那不就行了,这就是深拷贝的由来。
function deepClone(sourceObj) {
let targetObj = Array.isArray(sourceObj) ? [] : {};
Object.keys(sourceObj).forEach(key => {
let value = sourceObj[key];
if (typeof(value) === 'object') {
if (value instanceof Object) { //一位老哥的写法 原型链我还没看----存疑
targetObj[key] = deepClone(value);
} else {
targetObj[key] = sourceObj[key];
}
} else if (typeof(value) === 'function') {
targetObj[key] = eval(value.toString()) //安全性问题
} else {
targetObj[key] = sourceObj[key];
}
})
return targetObj;
}
let obj2 = deepClone(obj);
console.log(obj2);
obj2.child.age = 21
console.log(obj.child); //{23}
其他方法:
- contact /slice
let arr = [1, 2, 3, [1, 4, 5]]
let arr2 = [].concat(arr);
console.log(arr2);
arr2[3][0] = 2
console.log(arr); //[1, 2, 3, [2, 4, 5]]
但是:一层可以深拷贝,如果是多层或是对象只能浅拷贝,slice同理。
- Object.assign/create
Object.assign(target, …sources)
用于将所有可枚举属性的值从一个或多个源对象分配到目标对象。它将返回目标对象。
let obj = {
name: '张三',
child: {
age: 23
}
}
let tar = {}
Object.assign(tar, obj);
console.log(tar);
tar.name = '李四';
tar.child.age = 21;
console.log(obj); //张三 21
所以说还是一层深拷贝。create也是。
注意:
Object.assign 方法只会拷贝源对象自身的并且可枚举的属性到目标对象
继承和不可枚举属性不会拷贝
-
es6 中解构也是一层
-
JSON.parse()
用 JSON.stringify() 把对象转成字符串,再用 JSON.parse() 把字符串转成新的对象,可以实现对象的深复制。
let obj2 = JSON.parse(JSON.stringify(obj))
obj2.child.age = 21;
console.log(obj); //23
but :
look at this
let obj = {
name: '张三',
child: {
age: 23
},
x: function() {
}
}
- 它复制不了函数
- 能正确处理的对象只有 Number, String, Boolean, Array, 扁平对象,即那些能够被 json 直接表示的数据结构。RegExp 对象是无法通过这种方式深拷贝。
- 深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成 Object;深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成 Object;