JavaScript 引用类型指针与赋值运算顺序深度解析
通过 `a.x = a = {n:2}` 这一经典案例,深入剖析 JavaScript 引用类型指针的变化轨迹以及表达式从右向左的求值逻辑,解释为何 `a.x` 返回 `undefined` 而 `b.x` 指向新对象。
引用类型与指针机制
在 JavaScript 中,对象是引用类型。当执行变量赋值时,实际存储的是对象在内存中的地址(指针),而非对象本身。
var a = {n:1};
var b = a;
上述代码执行后,a 和 b 同时指向内存中同一个对象实例(不妨称其为对象 A):
此时,通过 a.x 或 b.x 访问的都是同一块内存地址的属性。
复杂表达式的求值顺序
接下来分析核心代码:a.x = a = {n:2}。要理解其结果,必须明确两个关键规则:一是运算符优先级,二是赋值操作符的求值方向。
第一步:计算左侧成员表达式 a.x
虽然赋值运算通常从右向左结合,但点操作符(.)的优先级远高于赋值操作符(=)。因此,引擎首先解析并计算最左边的 a.x。
由于当前 a 指向对象 A,这一步实际上是在对象 A 上新增了一个名为 x 的属性。因为尚未赋值,该属性值为 undefined:
此时,对象 A 的结构变为 {n:1, x: undefined}。因为 b 同样指向对象 A,所以 b.x 现在也拥有 undefined 值。
第二步:执行右侧赋值 a = {n:2}
根据从右向左的结合律,接着执行最右侧的赋值语句:
a = {n:2}
这里创建了一个全新的对象实例(称为对象 B,内容为 {n:2}),并将指针 a 重新指向了对象 B。此时变量状态如下:
a指向 对象 B(无x属性)。b依然指向 对象 A(拥有x: undefined属性)。
第三步:回补赋值 a.x = ...
最后执行剩余的赋值部分:a.x = [上一步的计算结果]。
许多人误以为这里的 a.x 会读取当前 a 的指向(即对象 B),但事实并非如此。JavaScript 引擎在第一步已经完成了对 a.x 的路径解析,确定它对应的是对象 A 的 x 属性。
因此,这步操作实际上是:将刚刚创建的 对象 B 整体赋值给 对象 A 的 x 属性:
最终结果与原理分析
为什么 console.log(a.x) 输出 undefined?
当前 a 指向对象 B({n:2})。当我们访问 a.x 时,JS 会在对象 B 及其原型链上查找 x 属性。对象 B 没有 x 属性,且 Object.prototype 中也不存在,因此返回 undefined。
为什么 console.log(b.x) 输出 [object Object]?
当前 b 依然指向对象 A。我们之前已经将对象 B 赋值给了对象 A 的 x 属性。因此,b.x 获取到的是对象 B 的引用。
由于 console.log 直接接收对象引用,浏览器调用该对象的隐式 toString() 方法将其转换为字符串,格式固定为 [object Object]。这并不代表两个对象,仅表示此处存放的是一个对象实例。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









