返回

浅尝辄止,难触本质——对象赋值与浅拷贝的奥秘揭晓

前端

在 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 也随之改变,因为它们都指向同一个对象。

总结

对象赋值和浅拷贝的区别在于,对象赋值只是复制对象的指针,而浅拷贝会创建一个新的对象,并复制原始对象的属性值。对象赋值会导致对其中一个对象的修改影响另一个对象,而浅拷贝不会。

在实际开发中,我们通常使用浅拷贝来创建新对象,因为浅拷贝可以避免对原始对象造成影响。但是,如果原始对象的属性值是复杂数据类型,我们需要使用深拷贝来创建一个完全独立的新对象。