关于 var x = y = 100 你真的会用吗?(下)

一道被无数人无数次地解释过的经典面试题:

    var a = { n:1 };
    a.x = a = { n:2 };
    console.log(a.x);

理解这道题的第一步需要搞懂这行代码:

    var x = y = 100;

相关内容在上一篇《关于 var x = y = 100 你真的会用吗?(上)》中已经介绍过了。

仔细看题目中的第二行,对比我们上面的代码,只是少了 var 关键字,如果把我们上面的代码也去掉 var 关键字,那么就变成:

    x = y = 100;

少了 var 关键字后,其中的 x 就变成了一个表达式,之所以这样,是因为 var/let/const 后跟随的一定是变量名,这样变量声明语句才是成立的。不至于与赋值行为混淆在一起。

因此,在 var 声明的语法中,变量名就不能写成 a.x 的样子。

再把两段核心代码放到一起分析下:

    var x = y = 100; // 语句1
    a.x = a = { n:2 }; // 语句2

结合上面的知识,我们初步可以分析出:

  • x 是一个标识符,而 y 和 100 都是表达式,且 y = 100 是一个赋值表达式。
  • a.x 是一个表达式,而 a = {n:2} 也是表达式,并且与上一条同理,后者的每一项也都是表达式。

如果上面可以理解,就接着向下分析:

  1. 在语句1中,并不存在连续的赋值运算,因为 var 从来都不进行计算求值,所以 var x = … 是值绑定操作,而不是将 … 赋值給 x。那么此语句中的唯一赋值运算,就是 y = 100。
  2. 再看语句2,实际上是两个连续的赋值表达式,按照上面的理解,计算求值是从左到右的,那么a.x是最先被计算求值的,正如刚分析的那样 a.x 是一个表达式,得到的结果是一个引用,这个表达式计算过程也是从左到右的,那么就分解出了 “a” 和 “.x”。

分步解析 a.x 表达式语义:

  • 计算表达式左侧 a,得到 a 的引用;
  • 将右侧的名字 x 理解为一个标识符,与 “.” 进行运算;
  • 计算 a.x 表达式的结果。

此时,我们得到了 a 的引用,那么带着如下几个问题再去从题目中找找答案。

  1. a 是什么呢?
  2. a.x 表达式发生了什么?
  3. a.x 输出什么?

再看一下完整的代码:

    var a = { n:1 };
    a.x = a = { n:2 };
    console.log(a.x);
  • 第一行代码中,声明了变量 a,并绑定了初始值 {n: 1},注意这里,严格意义上说是绑定值而不是赋值;
  • 紧接着第二行代码中的第一个表达式计算结束后,访问了 a 下面的 x 属性,那么这里就会暂存了 a 的引用,此时 a 为 {n: 1};
  • 接下来进行第二行代码的第二个赋值运算 a = {n: 2};
    • 此时左侧操作数 a 与上一次暂存的值是相同的;
    • 但是接下来的 “=”,使之发生赋值操作,左侧操作数 a 作为一个引用被覆盖了,这个引用仍然是当前上下文中的那个变量 a;
  • 记得我们之前暂存的 a 的引用么,这个暂存的 a 并不会随之更新,因为 a = {n: 2} 是一个运算结果,这个结果有且只有引擎知道;
  • 接下来代码就变成了这样一个赋值语句,等号左侧是"已经求过值的 a.x",且这个 a 的引用在之前已经暂存过了 (指向的是 {n: 1} );
  • a.x 这个被赋值的引用其实是一个未创建的属性,赋值操作将使得原始的 a(之前被暂存的)拥有一个新属性 x;
  • 不过因为第二个赋值表达式的原因,原始的 a 已经被新产生的 a 覆盖了,新的值为 {n: 2};
  • 那么我们之前暂存的原始 a 就在引用传递过程中丢失了,同理 a.x 也被丢弃,变得毫无意义;
  • a.x 变得没有意义,那么对 a.x 的赋值操作也是无意义的。

通过分析可以得出结论,打印 a.x 时,虽然此时的 a 是存在的,但是这个新产生的 a 内部并没有一个 x 属性,因此输出 undefined。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值