java 连等_关于赋值和连等

理解 赋值过程 与 连等 的右结合性

(copy了原文以及文末链接,开篇是一个瓜(例子),文末阐明机理)

有这样一个热门问题:

var a = {n: 1};

var b = a;

a.x = a = {n: 2};

alert(a.x); // --> undefined

alert(b.x); // --> {n: 2}

其中:

console.log(a); // --> {n: 2}

console.log(b); // --> {n: 1,x: {n: 2}}

console.log(b.x === a); // --> true

并且b.x = a = {n: 2};与a.x = a = {n: 2};是完全等价的。

因为在解析a.x或b.x的那个时间点。a和b这两个名称指向同一个对象。

其实这个问题很好理解,关键要弄清下面两个知识点:

JS引擎对赋值表达式的处理过程

赋值运算的右结合性

一. 赋值表达式

形如

A = B

的表达式称为赋值表达式。其中A和B又分别可以是表达式。B可以是任意表达式,但是A必须是一个左值。

所谓左值,就是可以被赋值的表达式,在ES规范中是用内部类型引用(Reference)描述的。例如:

表达式foo.bar可以作为一个左值,表示对foo这个对象中bar这个名称的引用;

变量email可以作为一个左值,表示对当前执行环境中的环境记录项envRec中email这个名称的引用;

同样地,函数名func可以做左值,然而函数调用表达式func(a, b)不可以。

那么JS引擎是怎样计算一般的赋值表达式A = B的呢?简单地说,按如下步骤:

计算表达式A,得到一个引用refA;

计算表达式B,得到一个值valueB;

将valueB赋给refA指向的名称绑定;

返回valueB。

二. 结合性

所谓结合性,是指表达式中同一个运算符出现多次时,是左边的优先计算还是右边的优先计算。

赋值表达式是右结合的。这意味着:

A1 = A2 = A3 = A4

等价于

A1 = (A2 = (A3 = A4))

三. 连等的解析

好了,有了上面两部分的知识。下面来看一下JS引擎是怎样运算连等赋值表达式的。

以下面的式子为例:

Exp1 = Exp2 = Exp3 = Exp4

首先根据右结合性,可以转换成

Exp1 = (Exp2 = (Exp3 = Exp4))

然后,我们已经知道对于单个赋值运算,JS引擎总是先计算左边的操作数,再计算右边的操作数。所以接下来的步骤就是:

计算Exp1,得到Ref1;

计算Exp2,得到Ref2;

计算Exp3,得到Ref3;

计算Exp4,得到Value4。

现在变成了这样的:

Ref1 = (Ref2 = (Ref3 = Value4))

接下来的步骤是:

将Value4赋给Exp3;

将Value4赋给Exp2;

将Value4赋给Exp1;

返回表达式最终的结果Value4。

注意:这几个步骤体现了右结合性。

总结一下就是:

先从左到右解析各个引用,然后计算最右侧的表达式的值,最后把值从右到左赋给各个引用。

四. 问题的解决

现在回到文章开头的问题。

首先前两个var语句执行完后,a和b都指向同一个对象{n: 1}(为方便描述,下面称为对象N1)。然后来看

a.x = a = {n: 2};

根据前面的知识,首先依次计算表达式a.x和a,得到两个引用。其中a.x表示对象N1中的x,而a相当于envRec.a,即当前环境记录项中的a。所以此时可以写出如下的形式:

[[N1]].x = [[encRec]].a = {n: 2};

其中,[[]]表示引用指向的对象。

接下来,将{n: 2}赋值给[[encRec]].a,即将{n: 2}绑定到当前上下文中的名称a。

接下来,将同一个{n: 2}赋值给[[N1]].x,即将{n: 2}绑定到N1中的名称x。

由于b仍然指向N1,所以此时有

b <=> N1 <=> {n: 1, x: {n: 2}}

而a被重新赋值了,所以

a <=> {n: 2}

并且

a === b.x

五. 最后的最后

如果你明白了上面所有的内容,应该会明白a.x = a = {n:2};与b.x = a = {n:2};是完全等价的。因为在解析a.x或b.x的那个时间点。a和b这两个名称指向同一个对象,就像C++中同一个对象可以有多个引用一样。而在这个时间点之后,不论是a.x还是b.x,其实早就不存在了,它已经变成了那个内存中的对象.x了。

最后用一张图表示整个表达式的运算过程:

a98cb63388de3fcff2ff1ac578b6f29f.png

转载自:https://segmentfault.com/a/1190000004224719 感谢分享!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值