Javascript中的浅拷贝与深拷贝
目录
一、Javascript中的浅拷贝与深拷贝概述
JavaScript 中的浅拷贝和深拷贝是常见的两种对象复制方式,它们分别从不同的角度来复制对象的属性和方法。
1. 浅拷贝(Shallow Copy)
浅拷贝会创建一个新的对象,然后将原始对象中的所有属性和方法都复制到新的对象中。但是,如果原始对象中有一些属性的值是对象或数组,那么浅拷贝只会复制它们的引用,而不是复制实际的对象或数组。因此,如果在浅拷贝后修改了原始对象中的这些属性,那么新对象中的对应属性也会被修改。
示例代码:
let obj1 = { name: 'John', age: 26, hobbies: ['reading', 'music'] };
let obj2 = Object.assign({}, obj1);
obj1.name = 'Tom';
obj1.hobbies.push('sports');
console.log(obj1);
// { name: 'Tom', age: 26, hobbies: ['reading', 'music', 'sports'] }
console.log(obj2);
// { name: 'John', age: 26, hobbies: ['reading', 'music', 'sports'] }
上述代码中,先创建了一个包含 name、age 和 hobbies 属性的对象 obj1,hobbies 属性的值是一个包含两个元素的数组。然后使用 Object.assign 方法将 obj1 的所有属性都复制到一个新的对象 obj2 中。接下来,修改 obj1 的 name 和 hobbies 属性,并将一个新的元素添加到 hobbies 数组中,结果显示出 obj1 和 obj2 的区别。
2. 深拷贝(Deep Copy)
深拷贝也会创建一个新的对象,并将原始对象中所有属性和方法都复制到新的对象中。但是,与浅拷贝不同的是,深拷贝会复制所有的嵌套属性和数组,而不仅仅是它们的引用。因此,在深拷贝后,新对象和原始对象中的所有属性和方法都是完全独立的,修改一个对象不会影响另一个对象。
示例代码:
let obj1 = { name: 'John', age: 26, hobbies: ['reading', 'music'] };
let obj2 = JSON.parse(JSON.stringify(obj1));
obj1.name = 'Tom';
obj1.hobbies.push('sports');
console.log(obj1);
// { name: 'Tom', age: 26, hobbies: ['reading', 'music', 'sports'] }
console.log(obj2);
// { name: 'John', age: 26, hobbies: ['reading', 'music'] }
上述代码中,实现深拷贝的方法是使用 JSON.stringify 和 JSON.parse 来序列化和反序列化对象。先创建一个包含 name、age 和 hobbies 属性的对象 obj1,hobbies 属性的值是一个包含两个元素的数组。然后使用 JSON.stringify 将 obj1 序列化为一个字符串,接着使用 JSON.parse 将这个字符串反序列化为一个新的对象 obj2。接下来,修改 obj1 的 name 和 hobbies 属性,并将一个新的元素添加到 hobbies 数组中,结果显示出 obj1 和 obj2 的区别。
二、Javascript中的浅拷贝与深拷贝概述
JavaScript 中的浅拷贝和深拷贝可以通过多种方式实现。
1. 浅拷贝(Shallow Copy)
a. 使用数组的浅拷贝
const arr1 = [1, 2, 3];
const arr2 = arr1.slice(); // 浅拷贝
b. 使用对象的浅拷贝
const obj1 = { a: 1, b: 2 };
const obj2 = obj1; // 浅拷贝
c. 使用ES6的扩展运算符 … 和赋值操作符
const obj1 = { a: 1, b: 2 };
const obj2 = [...obj1]; // 浅拷贝
const arr1 = [1, 2, 3];
const arr2 = [...arr1]; // 浅拷贝
d. 使用Object.assign()方法
const arr1 = [1, 2, 3];
const arr2 = [...arr1]; // 浅拷贝
2. 深拷贝(Deep Copy)
a. 递归拷贝每一个属性
deepCopy: function(obj) {
// 判断是否为 null、undefined 或空对象
if (obj === null || obj === undefined || obj.nodeType === null) {
return obj;
}
// 如果是对象,则递归拷贝每一个属性
if (Array.isArray(obj)) {
return [...obj];
}
// 如果是数组,则递归拷贝每一个元素
if (Array.isArray(obj[0])) {
return [...obj[0]];
}
// 如果是字符串,则递归拷贝每一个字符
if (typeof obj === 'string') {
return JSON.parse(JSON.stringify(obj));
}
// 如果是 Date 对象,则递归拷贝每一个日期部分
if (typeof obj === 'object' && obj.constructor === Date) {
return new Date(...obj.getTime());
}
return obj;
}
let myObj = { a: { b: { c: 'Hello' }, d: true }, e: [1, 2, 3], f: 123 };
console.log('Deep Copy:', this.deepCopy(myObj));
b. 使用 JSON.parse 和 JSON.stringify
let obj1 = { a: 1, b: { c: 2 } };
let obj2 = JSON.parse(JSON.stringify(obj1));
但是要注意,使用 JSON.stringify 和 JSON.parse 可能存在一些问题,例如一些特殊的数据类型,如 RegExp、Function、Date 等,在序列化和反序列化时可能会失效。
c. 使用第三方库,如 Lodash、Immutable 等。
let obj1 = { a: 1, b: { c: 2 } };
let obj2 = _.cloneDeep(obj1); // 使用 Lodash
let obj3 = Immutable.Map(obj1); // 使用 Immutable
三、Javascript中的浅拷贝与深拷贝优缺点对比
1. 浅拷贝(Shallow Copy)
浅拷贝,即只复制一层对象属性,而不复制属性值所指向的对象。
浅拷贝的优点是:
1.简洁易懂,实现起来比较容易;
2.复制的对象是原对象的一份浅表副本,对副本的修改不会影响原对象。
浅拷贝的缺点是:
它只复制对象的一层,如果对象的属性值是一个引用类型,那么只会复制这个属性值的引用,而不是复制整个引用类型的对象。
这就意味着,对浅拷贝后的对象进行修改,很可能会改变原对象。这种缺点在多层嵌套的对象中会更加明显。
2. 深拷贝(Deep Copy)
深拷贝,会完全复制整个对象,包括对象中的所有嵌套属性,这样就避免了浅拷贝中的缺点。
深拷贝的优点是:
1. 完全复制了整个对象,对副本的修改不会影响原对象;
2. 不受对象层次结构的限制,可以复制多层嵌套的对象。
深拷贝的缺点是:
深拷贝的实现通常比浅拷贝复杂得多,而且会消耗更多的计算资源。对于大型对象或多层嵌套的对象,深拷贝的效率和性能可能会变得很低。
因此,在实际开发中,需要根据具体情况选择浅拷贝还是深拷贝。如果原对象中没有多层嵌套的对象,或者只需要复制对象的一层属性,那么可以使用浅拷贝;如果需要完全复制整个对象,那么可以使用深拷贝。