• 纠结的连等赋值


      偶的看到一段有意思的代码:

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

      作为一个热衷于“钻牛角尖”的人,楼主对这样的代码很感兴趣,也不禁陷入了思考。so也不要说写这样的代码难维护啥的,纯粹为了思考逻辑。

      首先,这是一个连等赋值,而且赋值的是个对象。如果是基本的JavaScript类型,不存在引用,也就不会有类似的问题,但是逻辑是一样的。

      

      赋值过程是怎么样的呢?以上的翻译是,b先赋值5,然后(b=5)会返回所赋的值(也就是5),然后再赋值给a,也就是:

    a = (b = 5);

      所以最初的代码,可以修改成:

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

      如果是这样,那么以下代码有什么区别:

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

      很明显,结果不一样,继续了解下JavaScript的运算顺序。

    var a = 10;        
    function fn() {
        a = 20;
        return 20;
    }
    
    var b = a + fn();
    console.log(b);

      输出30,我们猜测JavaScript是从左到右运算的(事实也确实如此)。先取出a在内存中的值(10),然后执行fn函数,返回20(同时改变了a的值),10+20=30。

      如果运算过程中有括号啥的,是不是会“智能”地改变运算顺序呢?

    var a = 10;        
    function fn() {
        a = 20;
        return 20;
    }
    
    var b = a + (fn() * 2);
    console.log(b);

      输出50,还是从左到右,没有智能地先运算括号里的内容,然后改变a的值,再和a相加。这在JavaScript内核中是怎么实现的?这个我也没有研究过,但是我知道C++等语言是没有这么“智能”的,可以通过堆栈来模拟,比如简单计算器

      再回头看这道题,声明一个变量a,指向一个对象{n: 1},然后执行连等。可以肯定的是,a.x和a指向的是同一块内存,我们从左到右运算,a.x实际操作的是a指向的对象,发现没有x这个key,那么就会自动添加,它的值等待右边的运算结果。然后a重新引用了一个对象,并且之前的{n:1}这个对象新的key(x)的value也引用到同一个对象上。大概过程如下图,过程2我把它理解为等待,等待过程3中a的运算结果。

      如果要说的稍微“专业”一点,连等是先确定所有变量的指针,再让指针指向那个赋值

      事实上,解析器在接受到 a.x = a = {n:2} 这样的语句后,会这样做:

    1. 找到 a 和 a.x 的指针。如果已有指针,那么不改变它。如果没有指针,即那个变量还没被申明,那么就创建它,指向 null。
      a 是有指针的,指向 {n:1};a.x 是没有指针的,所以创建它,指向 null。
    2. 然后把上面找到的指针,都指向最右侧赋的那个值,即 {n:2}

      如果理解了,试试这道题吧:

    var a, b, c, d;
    a = b = c = d = {a: 1};
    a.x = a = b.y = b = c.z = c = {}
    console.log(a, b, c, d);

    参考:

    1. Operator_Precedence
    2. javascript 连等赋值问题
  • 相关阅读:
    v-bind 和v-model 的区别
    解决PC端和移动端自适应问题?
    安全解决将字符串" "转换成换行
    最全的正则表达式-匹配中英文、字母和数字(转)
    vue:style标签中的scoped属性(作用域)和lang属性的介绍
    vue项目main.js文件下import router from './router'默认导入router文件夹下index.js的原因
    VUE修改样式无效
    lodop如何获取打印机名称
    深拷贝和浅拷贝
    Vue.js学习笔记:props传递数据(转)
  • 原文地址:https://www.cnblogs.com/lessfish/p/4630656.html
Copyright © 2020-2023  润新知