首先来看一段代码:
1
2
3
|
var o = {a:1};
o.b = o = {a:2};
alert(o.b); // undefined
|
以上第二句 o.b = o = {a:2} 是一个连续赋值表达式。那么在这个过程中究竟发生了什么呢?
在ECMAScript(3rd)文档中有关于赋值表达式的解释:
The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows:
- Evaluate LeftHandSideExpression.
- Evaluate AssignmentExpression.
- Call GetValue(Result(2)).
- Call PutValue(Result(1), Result(3)).
- Return Result(3).
左侧得出的是引用,右侧调用GetValue取得的是确定值。
然后我们来分析 o.b = o = {a:2} 这个表达式。假设 {a: 1} 这个对象为 obg1,{a: 2} 这个对象为obg2,全局为global。
上述表达式的解析过程如下:o.b = Expr
首先解析 o.b = expr
- 先取得引用 (obj1, "b") 。
- 然后解析 Expr
ession1 。这个解析过程的步骤如下: - 先取得引用 (global, "o") 。
- 求赋值表达式的值: obg2 。
- 取得步骤 b 中的结果: obg2 。
- 将步骤 c 的结果赋值给步骤 a 的结果,即把 obg2 赋值给 (global, "o") 。
- 返回步骤 c 的结果,即 obg2 。
- 取得步骤 2 中的结果: obg2 。
- 将步骤 3 的结果赋值给步骤1的结果,即把 obg2 赋值给 (obj1, "b") 。
- 返回步骤 3 的结果,即 obg2 。
结果即为:
obg1: {a: 1, b: obg2}
obg2: {a: 2}
我们常说赋值运算是从右至左,是指右边先结合。如果理解为右边先运算就会有误解了,虽然右边先赋值成功。