这是一个包含两个赋值运算符的复合表达式:
var a = {n: 1};
var b = a;
a.x = a = {m: 2};
a; // => {m: 2}
b; // => {n: 1, x: {m: 2}}
棘手的部分是第三行:
a.x = a = {m: 2};
恕我直言,赋值运算符=
是右结合的,所以表达式的嵌套结构是:
a.x = (a = {m: 2});
但是 ES5 中的求值顺序始终是从左到右,根据ES5 Annex D .
The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows:
- Let lref be the result of evaluating LeftHandSideExpression.
- Let rref be the result of evaluating AssignmentExpression.
- Let rval be GetValue(rref).
- Throw a SyntaxError exception if the following conditions are all true: ....omitted intentionally to save space
- PutValue(lref, rval).
- Return rval.
所以我对从左到右的评估顺序的理解是:
- 首先评估
a.x
并为其返回一个引用lref1
计算
a = {m: 2}
得到rref1
,因为它也是一个赋值表达式,我们将再次开始这个过程(就像递归一样) )2.1。首先评估
a
并返回它的引用lref2
2.2。评估
{m: 2}
并将对象{m: 2}
返回为rref2
2.3。令
rval2
=GetValue(rref2)
,因此rval2
也是对象{m: 2}
2.4。
PutValue(lref2, rval2)
,因此a
将重新绑定(bind)对象{m: 2}
而不是{n: 1}
2.5。返回
rval2
,即对象{m: 2}
为rref1
(不是引用类型,而是对象)让
rval1
=GetValue(rref1)
,这也是对象{m: 2}
PutValue(lref1, rval1)
,因此lref1
引用的内存地址将为{m: 2}
。并且b.x
仍然引用该地址并且b
将被更新。
此过程符合 ES5 规范并很好地解释了结果。
我的问题是:
上述评估顺序是真是假?如果错误,还有其他解释吗?
如何正确理解ES5中的引用规范类型?它只是一个引用某个内存地址的中间指针吗?
最佳答案
是的,您对运算符顺序的理解似乎是正确的。
A Reference consists of three components, the base value, the referenced name and the Boolean valued strict reference flag. The base value is either undefined, an Object, a Boolean, a String, a Number, or an environment record (10.2.1).
从属性访问创建引用的过程在 11.2.1 中定义。 :
- Return a value of type Reference whose base value is baseValue and whose referenced name is propertyNameString, and whose strict mode flag is strict.
因此引用lref1
保存 a
的对象值 (以及引用的名称字符串 "x"
),您最初使用 {n: 1}
创建该字符串。引用并不关心它来自的变量;它只关心创建时提供的基值和引用名称。
更改 a
所持有的值对引用 lref1
所持有的基值没有任何影响。 lref1
继续保持a
的原始值(即 {n: 1}
对象)无论 a
是什么创建 lref1
之后执行.
简而言之,从表达式 a.x
创建的引用与变量 a
不再有任何关系一旦创建引用。相反,引用只知道 a
所保存的值。在创建引用时。
关于javascript - JavaScript 中包含两个赋值运算符的复合表达式的求值过程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30716349/