先看上面这个问题:
var a = {n: 1};
var b = a;
a.x = a = {n: 2};
console.log(a.x); // --> ?
console.log(b.x); // --> ?
要解决这个问题,须要了解:
- JS 引擎对赋值表达式的解决
- 赋值运算的右联合性
赋值表达式
形如
A = B
的表达式称为赋值表达式,其中 A 和 B 又别离能够是表达式。B 能够是任意表达式,然而 A 必须是一个 左值。
左值:能够被赋值的表达式,在 ES 标准中是用外部类型 援用 (Reference) 形容的。
JS 引擎会按如下步骤解决赋值表达式:
- 计算表达式 A,失去一个援用
ArRf
; - 计算表达式 B,失去一个援用
BRef
; - 通过
GetValue(BRef)
,失去一个值BValue
- 解析
ARef
,如满足肯定条件(不是左值的条件),会报SyntaxError
异样 - 通过
PutValue(ARef, BValue)
进行赋值 - 返回
BValue
赋值运算的右联合性
赋值表达式是右联合的。即:
Exp1 = Exp2 = Exp3 = Exp4
等价于
Exp1 = (Exp2 = (Exp3 = Exp4))
连等赋值解析
依据下面两局部的常识,连等赋值的解析如下:
=> Exp1 = (Exp2 = (Exp3 = Exp4))
=> Ref1 = (Ref2 = (Ref3 = Ref4))
=> Ref1 = (Ref2 = (Ref3 = GetValue(Ref4)))
=> Ref1 = (Ref2 = (Ref3 = Value4))
=> Ref1 = (Ref2 = Value4)
=> Ref1 = Value4
=> Value4
总结一下就是:先从左到右解析各个援用,而后计算最右侧的表达式的值,最初把值从右到左赋给各个援用。
当初回到结尾的问题,前两个 var 语句执行完后,a
和 b
都指向同一个对象{n: 1}
,对于
a.x = a = {n: 2};
先从左到右先解析各个援用,因而 a.x
中的 a
指向的是对象 {n: 1}
,b
和此时的 a
指向的是同一个对象
接着 a
被从新赋值为 {n: 2}
,再而后a.x
被赋值{n: 2}
,于是失去
console.log(a.x) // undefined
console.log(b.x) // {n: 2}
参考
由 ES 标准学 JavaScript(二):深刻了解“连等赋值”问题
12.3 Left-Hand-Side Expressions
11.13.1 Simple Assignment (=)