浅尝辄止,难触本质——对象赋值与浅拷贝的奥秘揭晓
2024-01-04 18:11:10
在 JavaScript 世界里,对象赋值和浅拷贝经常让人傻傻分不清楚,但实际上它们之间存在着天壤之别。要理解这两者的差异,首先需要了解 JavaScript 的内存管理机制。
栈与堆
JavaScript 内存主要分为栈内存和堆内存。栈内存存储基本数据类型(如数字、字符串、布尔值)和指向堆内存的指针。堆内存存储复杂数据类型(如对象、数组、函数)的实际数据。
当我们声明一个对象时,该对象会被存储在堆内存中,并返回一个指向该对象的指针,该指针存储在栈内存中。也就是说,当我们对一个对象的属性进行操作时,实际上是通过栈内存中的指针来访问堆内存中的数据。
对象赋值
对象赋值只是简单地将一个对象的指针赋给另一个变量。这意味着两个变量都指向同一个对象,对其中一个变量的修改也会影响另一个变量。
举个例子,我们有如下代码:
const obj1 = {
name: 'John Doe',
age: 30
};
const obj2 = obj1;
obj2.name = 'Jane Doe';
console.log(obj1); // { name: 'Jane Doe', age: 30 }
console.log(obj2); // { name: 'Jane Doe', age: 30 }
在上面的代码中,obj2
被赋值为 obj1
,因此 obj2
指向同一个对象。当我们修改 obj2.name
时,obj1.name
也随之改变,因为它们指向同一个对象。
浅拷贝
浅拷贝会创建一个新的对象,然后遍历原始对象,如果原始对象的属性值是基本数据类型,则直接复制该值;如果原始对象的属性值是复杂数据类型,则浅拷贝只会复制该属性值的指针。
举个例子,我们有如下代码:
const obj1 = {
name: 'John Doe',
age: 30,
address: {
street: '123 Main Street',
city: 'Anytown',
state: 'CA'
}
};
const obj2 = Object.assign({}, obj1);
obj2.name = 'Jane Doe';
console.log(obj1); // { name: 'John Doe', age: 30, address: { ... } }
console.log(obj2); // { name: 'Jane Doe', age: 30, address: { ... } }
在上面的代码中,我们使用 Object.assign()
方法对 obj1
进行浅拷贝,创建了新的对象 obj2
。当我们修改 obj2.name
时,obj1.name
不会改变,因为它们指向不同的对象。但是,当我们修改 obj2.address.street
时,obj1.address.street
也随之改变,因为它们都指向同一个对象。
总结
对象赋值和浅拷贝的区别在于,对象赋值只是复制对象的指针,而浅拷贝会创建一个新的对象,并复制原始对象的属性值。对象赋值会导致对其中一个对象的修改影响另一个对象,而浅拷贝不会。
在实际开发中,我们通常使用浅拷贝来创建新对象,因为浅拷贝可以避免对原始对象造成影响。但是,如果原始对象的属性值是复杂数据类型,我们需要使用深拷贝来创建一个完全独立的新对象。