我们使用Object.assign(target,…sources)时,其实只是浅拷贝。只能复制第一层属性,而如果第一层属性中有对象或数组的话,其实只是对对象或数组的引用而已。
我们修改target里的对象属性时,source对象中对应的对象属性也会改变
let source = {
age: 'nice',
obj: {
name: 'nice'
}
}
let target = {
}
Object.assign(target, source)
target.obj.name = 'change'
console.log(target.obj.name) //change
console.log(source.obj.name) //change
要想实现深拷贝:
function deepCopy(target, source) {
if (source == null) {
return
}
for (let i in source) {
if (Object.prototype.hasOwnProperty.call(source, i)) {
console.log(i)
console.log(typeof i)
if (typeof source[i] == 'object') {
target[i] = {
}
deepCopy(target[i], source[i])
} else {
target[i] = source[i]
}
}
}
}
需要注意的是 for …in 循环中读取出来的变量都转换成string了,所以在递归传参一定要注意用
deepCopy(target[i], source[i])
2020.9.6记
上面的深拷贝仅仅实现了对象的深拷贝,没有考虑到数组的情况。下面代码兼具了数组和对象:
function deepCopy(target) {
let result;
if (Object.prototype.toString.call(target) === "[object Array]") {
result = [];
target.forEach((element) => {
result.push(deepCopy(element));
});
} else if (Object.prototype.toString.call(target) === "[object Object]") {
result = {
};
Object.keys(target).forEach((key) => {
result[key] = deepCopy(target[key]);
});
} else {
result = target;
}
return result;
}
顺便总结一下js判断数据类型的几种方式和优缺点。
Object.prototype.toString.call() //这个方法是最好了,可以明确的区分各种类型
typeof //这个区分不出来数组和对象和null。
Array.isArray() //这个用来区分数组
instanceof //无法区分null 和 undefined