目录
使用 JSON.parse(JSON.stringify()) 进行深拷贝:
概念
在前端开发中,我们经常会遇到对数据进行拷贝的需求。拷贝可以分为深拷贝和浅拷贝两种方式。
浅拷贝指的是创建一个新的对象,新对象的引用类型属性仍然指向原对象的引用。也就是说,只拷贝了对象的引用,而没有拷贝对象本身。
深拷贝则是将原对象完全复制一份,包括对象的属性和引用类型的属性。也就是说,拷贝了对象本身和对象的引用。
实例
1.浅拷贝的实现方式
使用 Object.assign() 方法进行浅拷贝:
let obj1 = { name: 'Tom', age: 18 };
let obj2 = Object.assign({}, obj1);
console.log(obj2); // { name: 'Tom', age: 18 }
在这个例子中,通过 Object.assign() 方法将 obj1 对象的属性拷贝到了 obj2 对象中。这种方式只会拷贝对象的属性,而不会拷贝对象的引用。
使用扩展运算符(...)进行浅拷贝:
let obj1 = { name: 'Tom', age: 18 };
let obj2 = { ...obj1 };
console.log(obj2); // { name: 'Tom', age: 18 }
扩展运算符(...)可以将一个对象的属性解构到另一个对象中。这种方式和 Object.assign() 方法的效果是一样的。
2.深拷贝的实现方式:
使用 JSON.parse(JSON.stringify()) 进行深拷贝:
let obj1 = { name: 'Tom', age: 18, hobbies: ['reading', 'swimming'] };
let obj2 = JSON.parse(JSON.stringify(obj1));
console.log(obj2); // { name: 'Tom', age: 18, hobbies: ['reading', 'swimming'] }
JSON.stringify() 方法将对象转换为 JSON 字符串,然后再使用 JSON.parse() 方法将 JSON 字符串转换回对象。由于 JSON 格式不支持函数和 undefined,所以这种方式无法拷贝对象的函数和 undefined 属性。
使用递归进行深拷贝:
function deepClone(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
let result = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
result[key] = deepClone(obj[key]);
}
}
return result;
}
let obj1 = { name: 'Tom', age: 18, hobbies: ['reading', 'swimming'] };
let obj2 = deepClone(obj1);
console.log(obj2); // { name: 'Tom', age: 18, hobbies: ['reading', 'swimming'] }
这种方式通过递归的方式,遍历对象的属性,将对象的属性和引用类型的属性递归复制到新的对象中,实现了深拷贝。
注:这里使用了Object.prototype.hasOwnProperty.call(obj, key) 是因为直接使用obj.hasOwnProperty(key)导致ESLint报错。ESLint 不允许从目标对象调用 Object 原型方法。
报错如下
小结
浅拷贝只是拷贝了对象的引用,而不拷贝对象本身和对象的引用类型属性。深拷贝则是将对象完全复制一份,包括对象的属性和引用类型属性。
对于浅拷贝,可以使用 Object.assign() 方法或扩展运算符(...)进行实现;对于深拷贝,可以使用 JSON.parse(JSON.stringify()) 方法或递归进行实现。
需要注意的是,使用 JSON.parse(JSON.stringify()) 方法进行深拷贝时,无法拷贝对象的函数和 undefined 属性。在使用递归进行深拷贝时,需要处理循环引用的情况,否则会出现栈溢出的错误。