您的位置:

深入探讨JavaScript中的对象拷贝

一、浅拷贝

浅拷贝是指在JS中对象之间的引用关系,即拷贝源对象的引用,而不是源对象的副本。在浅拷贝中,源对象和目标对象会引用同一个内存地址中的内容,因此当源对象中的某个属性值发生改变时,目标对象中的相应属性值也会随之改变。

// 浅拷贝示例
let obj1 = { a: 10, b: { c: 20 } };
let obj2 = Object.assign({}, obj1);
obj1.b.c = 30;
console.log(obj2.b.c); // 30

如上述代码所示,当我们改变源对象obj1中的b.c属性值时,因为obj2是浅拷贝得到的,所以其相应属性值也被改变了。

然而,如果数值、字符串等基本数据类型的属性值发生改变,浅拷贝则不会发生变化,因为基本数据类型的值是存储在栈内存中的实际值,深浅拷贝都是拷贝了这个值。

二、深拷贝

深拷贝是指完全复制一个对象或多个嵌套对象的值,并将其复制到新的内存地址中。也就是说,源对象和目标对象是完全独立的,互不关联,互相之间的修改不会互相影响。

// 深拷贝示例
function deepClone(obj) {
    if (typeof obj !== 'object' || obj === null) {
        return obj;
    }
    // 根据obj的类型创建一个新的对象
    let newObj = Array.isArray(obj) ? [] : {};
    for (let key in obj) {
        // 判断一个对象是否是自己的属性
        if (obj.hasOwnProperty(key)) {
            // 递归调用复制函数
            newObj[key] = deepClone(obj[key]);
        }
    }
    return newObj;
}
let obj1 = { a: 10, b: { c: 20 } };
let obj2 = deepClone(obj1);
obj1.b.c = 30;
console.log(obj2.b.c); // 20

如上述代码所示,当我们改变源对象obj1中的b.c属性值时,目标对象obj2不会受到影响,因为它们是完全独立的。

三、序列化和反序列化

JavaScript中的对象可以通过JSON.stringify()方法序列化为JSON格式的字符串,然后再通过JSON.parse()方法反序列化为新的对象。

// 序列化和反序列化示例
let obj1 = { a: 10, b: { c: 20 } };
let str = JSON.stringify(obj1);
let obj2 = JSON.parse(str);
obj1.b.c = 30;
console.log(obj2.b.c); // 20

如上述代码所示,在将序列化后的JSON字符串反序列化为新的对象后,它们是完全独立的,相互之间不会产生影响。但是这种方法也有其缺点,因为在序列化和反序列化过程中,一些特殊的对象和属性,如Date、RegExp、Function等,在序列化时无法得到正确的表现,因此可能会导致一些不可预测的结果。

四、使用第三方库

除了上述三种方法外,还可以使用一些优秀的第三方库提供的对象拷贝方法,如jQuery的$.extend()方法、lodash的_.cloneDeep()方法等,这些方法都针对不同的应用场景提供了完善的解决方案。

// underscore.js/lodash类库提供深拷贝方法_.cloneDeep()的使用示例
let obj1 = { a: 10, b: { c: 20 } };
let obj2 = _.cloneDeep(obj1);
obj1.b.c = 30;
console.log(obj2.b.c); // 20

五、结语

JavaScript对象拷贝并不是一个简单的问题,根据应用场景的不同,选择不同的拷贝方式才能得到预期的结果。开发者需要多加注意,灵活选用不同的拷贝方法以满足应用需求。