JavaScript对象引用疑问:为何嵌套属性修改会同步至原对象?
JavaScript对象赋值与引用的核心原理
要搞懂你遇到的两种情况,关键得明白JavaScript里引用类型变量的存储逻辑:对象、数组这类引用类型,变量本身并不直接存对象内容,而是存一个指向堆内存中对象的地址引用。下面分两种情况拆解:
1. 重新赋值obj2为nestedObj,仅obj2变化的原因
先看对应代码:
const obj1 = { nestedObj: { foo2: 'bar' } }; let obj2 = obj1; // 第一步赋值 obj2 = obj2.nestedObj; // 重新赋值obj2
- 第一步
obj2 = obj1:把obj1里存储的「外层对象的引用地址」复制给了obj2,此时obj1和obj2指向堆内存中同一个外层对象。 - 第二步
obj2 = obj2.nestedObj:这是给obj2变量重新赋值,把它存储的引用地址换成了「nestedObj对象的地址」。这时候obj1的引用地址还是指向原来的外层对象,两者指向的对象已经不一样了,所以只有obj2发生变化,obj1不受影响。
2. 修改obj2的foo2,obj1同步变化的原因
对应代码:
const obj1 = { nestedObj: { foo2: 'bar' } }; let obj2 = obj1; obj2.nestedObj.foo2 = 'updated'; // 修改属性
obj2 = obj1后,两者指向同一个外层对象,而外层对象里的nestedObj也是一个引用类型,它的地址同样被存在外层对象中。- 当执行
obj2.nestedObj.foo2 = 'updated'时,你并没有修改obj2变量里的引用,而是顺着这个引用找到堆内存中的外层对象,再找到它的nestedObj引用指向的对象,最后修改这个对象的foo2属性。 - 因为obj1指向的外层对象和obj2的是同一个,它的
nestedObj引用也指向同一个子对象,所以obj1访问nestedObj.foo2时,看到的就是修改后的值。
关键区分:变量重新赋值 vs 对象属性修改
- 变量重新赋值(比如
obj2 = xxx):只是改变变量自身存储的引用地址,和原对象无关,其他指向原对象的变量不会受影响。 - 对象属性修改(比如
obj2.key = xxx):是直接在堆内存中修改对象本身,所有指向该对象的变量都会同步看到变化。
另外纠正一个常见误区:JavaScript是按值传递,但这里的「值」对于引用类型来说是「引用地址」。不是所谓的“引用传递”,因为赋值时是把引用地址复制了一份给新变量,两个变量的引用是独立的,只是指向同一个对象而已。
内容的提问来源于stack exchange,提问作者Marcelo Alarcon
相关产品推荐
相关产品推荐

