详解JS深拷贝与浅拷贝
一、什么是拷贝
在JavaScript中,我们经常需要对一个数据进行拷贝,这里的拷贝指的是将一个数据重新复制一份,从而在新的数据上进行操作,而原始数据不会受到影响。拷贝手段分为两种:浅拷贝和深拷贝。
1.1 浅拷贝
浅拷贝就是将原始数据的引用复制一份给新的数据,这样新数据和原始数据指向同一块内存区域,因此对新数据进行操作,也会影响原始数据。
示例代码:
let obj = {a: 1, b: {c: 2}};
let newObj = obj;
newObj.a = 3;
newObj.b.c = 4;
console.log(obj); // {a: 3, b: {c: 4}}
可以看到,对 newObj
进行操作,同时也影响了 obj
。
1.2 深拷贝
深拷贝是将原始数据完整地复制一份给新的数据,新数据和原始数据没有任何联系,对新数据的操作也不会影响原始数据。
示例代码:
let obj = {a: 1, b: {c: 2}};
let newObj = JSON.parse(JSON.stringify(obj));
newObj.a = 3;
newObj.b.c = 4;
console.log(obj); // {a: 1, b: {c: 2}}
console.log(newObj); // {a: 3, b: {c: 4}}
可以看到,对 newObj
进行操作,并不影响 obj
。
二、浅拷贝的实现方法
2.1 Object.assign()
Object.assign()
方法将所有的可枚举属性的值从一个或多个源对象复制到目标对象。它会先创建一个新对象,然后将源对象的属性拷贝到新对象上。
示例代码:
let obj1 = {a: 1,b: {c: 2}};
let obj2 = Object.assign({}, obj1);
obj2.a = 3;
obj2.b.c = 4;
console.log(obj1); // {a: 1, b: {c: 4}}
console.log(obj2); // {a: 3, b: {c: 4}}
可以看到,对 obj2
进行操作,并不影响 obj1
。
2.2 扩展运算符 ...
扩展运算符 ...
也可以实现浅拷贝。它能够将一个数组或对象展开成一系列参数,方便地将其插入一个函数或对象字面量中。
示例代码:
let obj1 = {a: 1,b: {c: 2}};
let obj2 = {...obj1};
obj2.a = 3;
obj2.b.c = 4;
console.log(obj1); // {a: 1, b: {c: 4}}
console.log(obj2); // {a: 3, b: {c: 4}}
可以看到,对 obj2
进行操作,并不影响 obj1
。
三、深拷贝的实现方法
3.1 手写递归函数
手写递归函数可以非常方便地实现深拷贝,它会遍历对象的所有属性和子属性,并将其转化为一个新的对象返回。
示例代码:
function deepClone(obj) {
let newObj = Array.isArray(obj) ? [] : {};
if (obj && typeof obj === "object") {
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = deepClone(obj[key]);
}
}
}
else {
newObj = obj;
}
return newObj;
}
let obj1 = {a: 1,b: {c: 2}};
let obj2 = deepClone(obj1);
obj2.a = 3;
obj2.b.c = 4;
console.log(obj1); // {a: 1, b: {c: 2}}
console.log(obj2); // {a: 3, b: {c: 4}}
可以看到,对 obj2
进行操作,并不影响 obj1
。
3.2 使用第三方包
第三方包 lodash
中的 _.cloneDeep()
方法也可以实现深拷贝。这个方法可以递归地复制一个 JavaScript 对象。
示例代码:
const _ = require('lodash');
let obj1 = {a: 1,b: {c: 2}};
let obj2 = _.cloneDeep(obj1);
obj2.a = 3;
obj2.b.c = 4;
console.log(obj1); // {a: 1, b: {c: 2}}
console.log(obj2); // {a: 3, b: {c: 4}}
可以看到,对 obj2
进行操作,并不影响 obj1
。
四、深度递归拷贝的注意事项
在深度递归拷贝中,需要注意以下几点:
- 对 Date、RegExp、Function 等对象无法进行深拷贝,需要特殊处理。
- 对于对象的循环引用,需要避免死循环。
五、总结
浅拷贝只是复制了一个对象的引用,而深拷贝则是复制了整个对象。使用递归函数实现深拷贝时,需要考虑到各种对象类型的情况。如果对数据的操作需要保证原始数据的不变性,建议使用深拷贝。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解JS深拷贝与浅拷贝 - Python技术站