杂乱无章

当前位置:首页 > 技术世界 > 杂乱无章

纠结的连等赋值

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

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 hereconsole.log(a.x);

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

var a = {n: 1};// a.x = (a = {n: 2});    // modified herea = {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 连等赋值问题

转载说明:欢迎转载本站所有文章,如需转载请注明来源于《绝客部落》。

本文链接:https://juehackr.net/zawen/61.html

相关内容

文章评论

表情

共 0 条评论
  • 这篇文章还没有收到评论,赶紧来抢沙发吧~