深拷贝
concat / slice
使用 concat / slice 可以实现对一个数组的浅拷贝
但是第一层为深拷贝 如何理解呢
我们创建两个数组
arr1 只有一层的数组
arr2 有两层的数组
然后我们用 concat() 或 slice() 分别拷贝两份数组
然后我们来修改拷贝后的数组
通过原数组是否会被影响 来验证是否为深拷贝
var arr1 = [1, 2, 4, 5, 6, 7, 8, 9];
var arr2 = [1, 2, 4, [5, 6, 7, 8, 9]];
var copyArr1 = arr1.concat();
var copyArr2 = arr2.concat();
copyArr1.push(10);
copyArr2[3].push(10);
console.log(arr1); // [1, 2, 4, 5, 6, 7, 8, 9]
console.log(arr2); // [ 1, 2, 4, [ 5, 6, 7, 8, 9, 10 ] ]
通过最终的输出 显然易见 这两个方法只能对第一层进行深拷贝
Object.assign(target, source......)
var obj = {
name: 'chou',
age: 18,
hobby: {
color: 'blue',
game: 'basketball',
},
};
var copyObj = Object.assign({}, obj);
copyObj.name = 'LuckyChou';
delete copyObj.hobby.color;
console.log(obj); // { name: 'chou', age: 18, hobby: { game: 'basketball' } }
同样的 通过结果 我们不难发现 Object.assign() 也只是实现了对象第一层的深拷贝
也就是对属性的深拷贝 如果属性值是引用类型的话 那么还是拷贝了它的地址
扩展运算符...
扩展运算符也能达到类似上述的效果 但是都是浅拷贝
const obj = {
name: 'chou',
age: 18
}
const arr = [1,2,3,4,5]
{...obj}
[...arr]
JSON.parse(JSON.stringify(obj))
var obj = {
name: 'chou',
age: 18,
hobby: {
color: 'blue',
game: 'basketball',
},
};
var copyObj = JSON.parse(JSON.stringify(obj));
copyObj.name = 'LuckyChou';
delete copyObj.hobby.color;
console.log(obj); // { name: 'chou', age: 18, hobby: { color: 'blue', game: 'basketball' } }
Wow! 通过结果 我们发现该方法居然实现了深拷贝 emmmmm 那么它有缺点吗
通过查阅MDN 我们可以找到这样一句话
undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略
也就是说对于 undefined 函数 symbol 用这种方法将无能为力
DIY
既然没有完美的方案可以实现深拷贝 那么我们自己动手实现一个吧
function deepClone(obj) {
function isObject(o) {
return (typeof o === 'object' || typeof o === 'function') && o !== null;
}
if (!isObject(obj)) {
throw new Error('非对象');
}
let isArray = Array.isArray(obj);
let newObj = isArray ? [...obj] : { ...obj };
Reflect.ownKeys(newObj).forEach((key) => {
newObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key];
});
return newObj;
}
由于深拷贝需要考虑到多种场景 实现起来也很困难 如果用于生产环境 推荐使用 lodash 的_clone 函数
Last updated
Was this helpful?