js 连等赋值 分析

JavaScript权威指南-第6版 4.11 赋值表达式 提到了连等赋值的情况,但是解释的不够详细,所以在此总结下;

首先看书上最重要的一句话:

image

这句话总结下就是:

A = B ; // 整个表达式返回 B

但是完整意义上是这样的:

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

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

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

  4. 返回valueB

第二句:

image

这句话总结下就是:

A1 = A2 = A3 = A4  // 等价于A1 = (A2 = (A3 = A4))

又因为前面所说,赋值表达式的值就是右操作数的值,所以

(A3 = A4) // 返回 A4
A1 = (A2 = (A3 = A4))
//等价于
//先 从左至右 计算好 A1,A2,A3 的引用,然后
A3 = A4
A2 = A4
A1 = A4

所以,汇总下:

A1 = A2 = A3 = A4

实际上就等价于:

//先 从左至右 计算好 A1,A2,A3 的引用,然后
A1 = A4; A2 = A4; A3 = A4;

好了,前面的看懂了,就来到这道神题,javascript 连等赋值问题

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

我第一次答的时候也错了,后来理理逻辑才对,下面分析分析,不过分析之前建议大家先看这篇:js 操作对象的引用和操作实际对象的区分

言归正传,上面的代码其实等价于下面这样:

var a = { n: 1 };
var b = a;
//先 从左至右 计算好 a,a.x 的引用,然后 a
= { n: 2 }; a.x = { n: 2 }; console.log(a.x); // --> undefined console.log(b.x); // --> {n:2}

关键是这段代码:

a.x = { n: 2 };

这段代码其实跟 a 并没有什么关系,因为 在为对象添加属性时,操作的是实际的对象。

所以,它仅仅是把对象 { n: 1 } 变成了 { n: 1, x: { n: 2 } },你可能疑问,在这个赋值前,a 的对象不就已经是 { n: 2 }了么?

不不不!看红色字体!!!

var a = { n: 1 };
var b = a;
//a.x = a = { n: 2 }; 先 从左至右 计算好 a,a.x 的引用,然后
a = { n: 2 };
a.x = { n: 2 };  //此时的 a 在赋值前就已经计算好引用了,实际上引用的是 { n:1 } 这个对象
console.log(a.x); // --> undefined  
console.log(b.x); // --> {n:2}

这样也反过来证明了前面赋值表达式 A=B 的逻辑;

add another demo

var total=0
async function add(num){
    // await only delay the assignment operation
    // that's how js works in assignment
    total=(console.log('executed sync',total)||total)+await (console.log('await execute after expression before')||num)
    console.log('res')
}
add(1)
add(2)
Promise.resolve().then(()=>{
    console.log(total)
})

参考资料:

JavaScript权威指南-第6版-中

由ES规范学JavaScript(二):深入理解“连等赋值”问题

javascript 连等赋值问题

原文地址:https://www.cnblogs.com/xianshenglu/p/8150163.html