zoukankan      html  css  js  c++  java
  • JS连等赋值的坑

    cnblogs标题: JS连等赋值的坑

    关于JS连等赋值有个经典的笔试题:

    var a = {n: 1};
    var b = a;
    a.x = a = {n: 2};
    
    console.log(a.x); // --> undefined
    console.log(b.x); // --> {n: 2}
    

    咋一看, 一脸懵逼, 这都什么玩意. 我一开始也是这个想法, 不过理解之后发现, 不是题目坑,
    确实自己水平还不到位. 本文先介绍理解上述笔试题需要的知识点, 然后对该笔试题详细分析.

    单个赋值表达式

    形如A = B的表达式被称为赋值表达式, 其中A和B又分别可以是表达式, B可以是任意表达式,
    而A必须是可以被赋值的表达式. 最关键的是我们要理解JS引擎是如何解析赋值表达式的:

    1. 先计算表达式A, 得到一个引用refA;
    2. 再计算表达式B, 得到一个值valueB;
    3. 将valueB赋给refA指向的位置;
    4. return valueB;

    这4个步骤最核心的是规定了, 必须先计算A, 再计算B. 我们在文末分析笔试题就会看到.

    多个连等解析

    A1 = A2 = A3 = A4, 知道单个赋值表达式的解析逻辑, 多个连等赋值就很容易类推. 出现
    多个连等, 我们完全可以给它分解成单个等号的形式. 比如上式可以分解成下面这样:

    A1 = (A2 = A3 = A4), 左边的A1看成单个赋值表达式中的A, 右边整体看成B. 继续分解,
    最终得出这样A1 = (A2 = (A3 = A4)). 因此这个连等的按步骤执行如下:

    1. 依次计算A1, A2, A3, 分别得到refA1, refA2, refA3;
    2. 计算A4得到valueA4, 把valueA4赋给A3;
    3. 把(A3 = A4)这个赋值表达式的返回值, 也就是value4赋给A2;
    4. 把(A2 = (A3 = A4))这个赋值表达式的返回值, 也就是value4赋给A1;

    大家不要蒙圈, 就在脑中这样想, 先计算左后计算右. 左边就单个A1, OK直接计算. 来到右
    边发现没法直接计算, 那么就把右边再分成左右, 按照这种思路循环递推就行.

    和学二叉树时候的思路, 简直如出一辙.

    再看笔试题

    var a = {n: 1};
    var b = a;
    a.x = a = {n: 2};
    console.log(a.x); // --> undefined
    console.log(b.x); // --> {n: 2}
    

    你可能会发现, 现在貌似还是不理解上面的代码到底发生了什么, 说明对JS中引用赋值, 理解还不
    够透彻.

    上面总共5行代码, 按顺序编号1-5.

    1. 首先执行前2行代码, 我们脑中大致有这样的图. a --> [ {n: 1} ] <--b, 说这是图太勉强, 大家
      将就看_. 这个图中间的[]表示这是个盒子, 盒子里面装有{n: 1}这个对象,ab都指向这个
      对象.
    2. 接下来, 到了全文最关键的时刻. 按照我们前面的分析, 第3行代码先执行a.x, 这时候我们上面的
      的图已经发生变化了, 变成这样a --> [ {n: 1, x: } ] <--b, 我们的x同学已经准备好了, 等着
      别人给它赋值呢.
    3. 再接着执行a, 我们的图没发生变化.
    4. 在接着执行{n: 2}, 大家注意这可是我们全新召唤出来的盒子, 盒子里面装有数据{n: 2}. 该
      盒子和前面的{n: 1}盒子没有任何关系(到目前为止).
    5. 为了方面我们就把第一次出现的盒子叫做盒子1, 第2次出现的的字叫做盒子2. 现在我们把盒子2赋给
      a, 我们的脑中将出现2个图. 图1[ {n: 1, x: } ] <--b, 图2a --> [ {n: 2} ]. 也就是说
      a已经指向了盒子2, 而b仍旧指向盒子1.
    6. 我们把a = {n: 2}这个表达式的返回值{n: 2}赋给x同学, 对就是x, x一直在等着呢, 现在
      没有a什么事了. 最终我们的图变成了这样, 图1[ {n: 1, x: {n: 2} } ] <--b,
      图2a --> [ {n: 2} ].

    我们上述6个步骤图的变化单门拿出来:

    a --> [ {n: 1} ] <--b
    
    a --> [ {n: 1, x: } ] <--b
    
    [ {n: 1, x: } ] <-- b
    a --> [ {n: 2} ]
    
    // 最终图
    [ {n: 1, x: {n: 2} } ] <--b
    a --> [ {n: 2} ]
    

    现在让我们输出什么, 我们就能输出什么.

    console.log(a.x);   // a现在指向的盒子2, 盒子2里没有x, 输出undefined
    console.log(b.x.n); // 2
    

    参考链接

    https://segmentfault.com/a/1190000004224719#articleHeader0

  • 相关阅读:
    opennebula 编译日志
    eclipse scons 使用指南
    eclipse 安装scons
    在Windows7上搭建Cocos2d-x 3.2alpha0开发环境
    Centos6.3 jekyll环境安装
    CNN-利用1*1进行降维和升维
    偏导数
    卷积神经网络--CNN
    struts2 模型驱动
    Struts2 数据驱动
  • 原文地址:https://www.cnblogs.com/asheng2016/p/7509510.html
Copyright © 2011-2022 走看看