0

这是一个包含两个赋值运算符的复合表达式:

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 Annex D,ES5 中的评估顺序总是从左到右。

根据ES5 第 11.13.1 节

产生式AssignmentExpression : LeftHandSideExpression = AssignmentExpression的评估如下:

  1. lref为评估LeftHandSideExpression的结果。
  2. rref为评估AssignmentExpression的结果。
  3. rval为 GetValue( rref )。
  4. 如果以下条件都为真,则抛出SyntaxError异常: ....有意省略以节省空间
  5. 放置值(lrefrval)。
  6. 返回rval

所以我对从左到右的评估顺序的理解是:

  1. 首先评估并为其a.x返回参考lref1
  2. 计算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将重新绑定对象{m: 2}而不是{n: 1}

    2.5. return rval2,即对象{m: 2}rref1(不是引用类型,而是对象)

  3. rval1= GetValue(rref1),这也是对象{m: 2}

  4. PutValue(lref1, rval1),所以lref1所指的内存地址就是{m: 2}。并且b.x仍然引用此地址并将b更新。

此过程符合 ES5 Spec 并很好地解释了结果。

我的问题是:

  1. 上述评价顺序是真是假?如果是假的,还有其他解释吗?

  2. 如何正确理解 ES5 中的参考规范类型?它只是一个指向某个内存地址的中间指针吗?

4

1 回答 1

1

是的,您对运营商订单的理解似乎是正确的。

ECMAScript 5 第 8.7 节说:

引用由三个部分组成,基值引用名称和布尔值严格引用标志。基值是未定义的、对象、布尔值、字符串、数字或环境记录 (10.2.1)。

从属性访问创建引用的过程在11.2.1中定义:

  1. 返回一个 Reference 类型的值,其基值为baseValue,其引用名称为propertyNameString,其严格模式标志为strict

因此,引用lref1保存了您最初使用创建的(以及引用的名称字符串)的对象值。引用不关心它来自的变量;它只关心创建时提供的基本值引用名称a"x"{n: 1}

更改所持有的a值对引用所持有的基值没有任何影响lref1。无论在创建. lref1_a{n: 1}alref1

简而言之,一旦创建引用,从表达式创建的引用a.x就不再与变量有任何关系a。相反,引用只知道a在创建引用时所持有的值。

于 2015-06-08T18:33:29.890 回答