为何对象类型变量始终与对象值同步?解析JS代码片段B的赋值逻辑
为什么JavaScript中引用类型赋值后修改原对象会影响新变量?
嘿,这个问题刚好戳中了JavaScript里原始类型和引用类型赋值的核心区别,咱们一步步把它捋明白~
先把你提到的两个代码片段放出来方便对比:
代码片段A(原始类型)
x = 5; y = x; x = 6; console.log(x); console.log(y); // 输出:6 5
代码片段B(引用类型)
x = {one: 5}; y = x; x.one = 6; console.log(x); console.log(y); // 输出:{one: 6} {one: 6}
先搞懂片段A的逻辑(原始类型值拷贝)
对于数字、字符串这类原始类型,变量存储的是实际的值:
- 执行
x = 5时,JavaScript会在栈内存里给x分配一个位置,把值5存在这里。 - 执行
y = x时,会把x存储的5完整拷贝一份,放到y的栈内存位置里。 - 之后
x = 6,只是把x的栈位置里的值改成了6,和y的那份拷贝完全没关系,所以最后log出来x是6,y是5。
再拆解片段B的核心(引用类型地址拷贝)
而对象、数组这类引用类型,逻辑就完全不一样了:
- 当你执行
x = {one: 5}时,JavaScript会在堆内存里创建这个对象{one:5}(因为对象可能体积较大,栈内存放不下),然后把这个对象在堆里的内存地址(比如0x123)赋值给变量x——也就是说x的栈内存里存的不是对象本身,而是指向对象的“门牌号”。 - 执行
y = x时,并不是把堆里的对象拷贝一份给y,而是把x存的那个“门牌号”(0x123)拷贝给了y。现在x和y的栈内存里存的是同一个门牌号,它们都指向堆里的同一个对象。 - 然后
x.one = 6这个操作,不是修改x的门牌号,而是顺着x的门牌号找到堆里的那个对象,把对象的one属性改成了6。因为y和x指向的是同一个对象,所以当你log(y)的时候,顺着y的门牌号找到的也是这个已经被修改过的对象,自然就会输出{one: 6}。
回应你的疑惑
你之前以为“在初始化y的时刻,x的值仍是{one:5},y应该等于{one:5}”,这个误区在于:你把y = x理解成了拷贝对象本身,但实际上拷贝的只是指向对象的地址。在y = x的瞬间,x和y确实都指向{one:5},但后续修改的是这个共享的对象,而不是x的地址,所以y自然能看到对象的变化。
打个比方:x和y都拿着同一个仓库的钥匙,x去仓库里把里面的东西换成了6,y再去开仓库门,看到的肯定也是换后的东西——而不是x复制了一个新仓库给y。
总结关键点
- 原始类型赋值是值拷贝:变量存实际值,修改一个不影响另一个。
- 引用类型赋值是地址拷贝:变量存堆内存地址,多个变量指向同一个对象,修改对象属性会影响所有指向它的变量。
内容的提问来源于stack exchange,提问作者tonitone110
相关产品推荐
相关产品推荐

