http://liunian.info/%E8%BF%9E%E7%BB%AD%E8%B5%8B%E5%80%BC%E4%B8%8E%E6%B1%82%E5%80%BC%E9%A1%BA%E5%BA%8F.html

看到一个2010 年的帖子[1],里面讨论了一段 JavaScript 代码:

1
2
3
var a = {n : 1 } ;
a. x = a = {n : 2 } ;  
alert (a. x ) ;     // --> undefined

帖子里有很多的讨论来分析为何 a.xundefined,下面是我的一些思考。

首先,在JavaScript中,有以下几点需要明确的:

  1. 可以说一切都是对象,一切都是引用调用。
  2. 赋值运算符(=)是除逗号运算符(,)外优先级最低的,并且是右结合的。[2]
  3. 求值顺序[3]是从左向右的[4]

1
2
3
4
5
6
7
8
9
10
11
a. x = a = {n : 2 } ;
// =>
a. x = (a = {n : 2 } ) ;
/*
 1. 首先,按 = 号的结合性做个分组;
 2. 然后,由于从左到右的求值顺序和运算符优先级,先计算 a.x,获得指向内存中的某个地址,假定为 A;
 3. 接着计算第一个等号的右边,其为第二个等号的求值结果: 把变量 a 指向对象 {n: 2}, 然后返回该引用;
 4. 然后把该引用赋给 A,即 A 位置存储的值是 {n: 2};
 在第三个步骤计算第二个等号的过程中,把 a 重新指向了另一个对象 {n: 2},而不在是 {n: 1} 了,
 这个时候 a.x 指向的位置已不在是 A 了,故最后得到的 a.x 是 undefined。
*/

不同于一些用于精简代码显示技术的 Trick,连续赋值应该说是较为常用的一种语句,但需要注意的是,尽量少写出这种修改、引用并存的语句。

 

http://www.iteye.com/topic/785445?page=2#1712357

==============================详细解答================================

嘛,这也是运算符结合性(associativity)与求值顺序(order of evaluation)的概念分不清楚时容易弄错的问题。
结合性和求值顺序是没有必然关系的。

JavaScript的表达式的求值顺序都是从左向右的。赋值运算的结合性虽然是右结合,但同样是从左向右求值的。看ECMAScript 5的附录D,
11.8.2, 11.8.3, 11.8.5: ECMAScript generally uses a left to right evaluation order, however the Edition 3 specification language for the > and <= operators resulted in a partial right to left order. The specification has been corrected for these operators such that it now specifies a full left to right evaluation order. However, this change of order is potentially observable if side-effects occur during the evaluation process.
这里的描述说明ECMAScript是使用从左向右的求值顺序

Ecmascript 5 grammar代码   收藏代码
  1. AssignmentExpression :  
  2.     ConditionalExpression  
  3.     LeftHandSideExpression AssignmentOperator AssignmentExpression  


这条语法规则定义了赋值运算符是右结合的。怎么看出来呢?
首先要能读懂ECMAScript规范里语法的记法。在冒号左边的是语法规则的名字,右边的是规则的推导内容。推导内容中,在同一行上的属于同一条子规则,在不同行上的属于不同子规则;不同子规则之间是“或”的关系。
上面的语法规则的意思是:
一个“赋值表达式”,
  可以由一个“条件表达式”构成;
  或者可以由一个“左手边表达式”加上一个“赋值运算符”加上一个“赋值表达式”构成。

如果在一条语法规则里,推导内容中出现了该规则自身,则这条规则是“直接递归”的。如果自身出现的位置在推导内容某条子规则的最左边,则为“左递归”,出现在最右边则为“右递归”。运算符结合性也正好在此体现:左递归的规则意味着左结合,右递归的规则意味着右结合。
可以看到,ECMAScript的赋值表达式的语法是右递归的,因而是右结合的。

这两者对程序执行有什么影响呢?前面clue的解答已经对路了。有兴趣看结合性、优先级和求值顺序的关系的例子的请参考我之前的一帖,虚拟机随谈(一):解释器,树遍历解释器,基于栈与基于寄存器,大杂烩,中间讲到抽象语法树的时候有举例。Java与C#同JavaScript一样,是用从左向右的求值顺序,而赋值运算是右结合的,所以那帖的例子也可以用来帮助理解JavaScript的状况。