一、浅拷贝
浅拷贝是指在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对象拷贝并不是一个简单的问题,根据应用场景的不同,选择不同的拷贝方式才能得到预期的结果。开发者需要多加注意,灵活选用不同的拷贝方法以满足应用需求。