JavaScript 深拷贝浅拷贝
在JavaScript的日常开发中,我们经常需要复制对象或数组。然而,由于JavaScript中的对象和数组是引用类型,简单的赋值操作可能会导致意外的结果。这就涉及到两个重要概念:浅拷贝和深拷贝。理解这两个概念对于编写健壮的JavaScript代码至关重要。
引用类型与基本类型
在探讨深浅拷贝之前,我们需要先了解JavaScript中的数据类型:
- 基本类型:存储的是值本身,包括Number、String、Boolean、null、undefined、Symbol和BigInt。
- 引用类型:存储的是内存地址的引用,包括Object、Array、Function等。
示例:
// 基本类型
let a = 5;
let b = a; // b复制了a的值
a = 10;
console.log(b); // 5 (b不受a变化影响)
// 引用类型
let obj1 = { name: 'Alice' };
let obj2 = obj1; // obj2引用了obj1的地址
obj1.name = 'Bob';
console.log(obj2.name); // 'Bob' (obj2随obj1变化而变化)
正是这种引用类型的特性使得我们需要在复制对象时格外小心。
什么是浅拷贝?
浅拷贝只复制对象的第一层属性。如果属性是基本类型,则复制其值;如果属性是引用类型,则复制其引用地址。
常用的浅拷贝方法
1. Object.assign()
let original = { name: 'Alice', address: { city: 'Beijing' } };
let copy = Object.assign({}, original);
// 改变基本类型属性
original.name = 'Bob';
console.log(copy.name); // 'Alice' (不受影响)
// 改变引用类型属性
original.address.city = 'Shanghai';
console.log(copy.address.city); // 'Shanghai' (受影响)
2. 展开运算符(Spread Operator)
let original = { name: 'Alice', address: { city: 'Beijing' } };
let copy = { ...original };
original.name = 'Bob';
console.log(copy.name); // 'Alice'
original.address.city = 'Shanghai';
console.log(copy.address.city); // 'Shanghai' (受影响)
3. 数组的浅拷贝方法
// 使用slice()
let arr1 = [1, 2, { x: 10 }];
let arr2 = arr1.slice();
// 使用展开运算符
let arr3 = [...arr1];
arr1[0] = 100;
console.log(arr2[0], arr3[0]); // 1 1 (不受影响)
arr1[2].x = 99;
console.log(arr2[2].x, arr3[2].x); // 99 99 (受影响)
备注
浅拷贝只解决了第一层属性的复制,对于多层嵌套的对象,内层对象仍然是共享的。
什么是深拷贝?
深拷贝会复制对象的所有层级属性,创建一个完全独立的新对象。无论原对象有多少层嵌套,深拷贝后的对象都与原对象完全隔离,互不影响。