JavaScript的连续赋值

Js文化,博大精深

网上一个讨论的很多的例子

var a = {n: 1};

var b = a;  

a.x = a = {n: 2};

console.log(a.x); //undefined

console.log(b.x);//{n: 2}

两个重点:

  • Js在处理连续赋值的时候,会先计算每一个变量,若它是一个指针,指向了一块内存地址,那么不会去变动它。若它未定义,则创建它指向null。

  • 一条语句只计算一次各个变量的地址,若中途改变,也不再计算。


我们走一次代码的流程:

  1. 创建a指针,指向{n: 1}的地址。

  2. 创建b指针,内容跟a一样,即b为a的拷贝,指向{n: 1}的内存地址

  3. 遇到一个连续赋值,检查每个变量。a.x未定义,则创建为一个指针,内容为null。a定义了,为{n: 1}的内存地址。Js不对其处理。

  4. 进行赋值操作。更改a指针的指向,指向{n: 2}。更改a.x指针的指向,为{n: 2}的内存地址。

  5. 关键在此 在a改变内容,指向{n: 2}后。a.x中的a还是指向{n: 1}的地址的,因为Js已经计算过一次变量了,不会进行第二次计算。一条语句只检查一次变量。

  6. 所以连续赋值的结果应该是这样的。a变为{n: 2}地址的指针。a.x也就是{n: 1}地址的x属性的地址。原来是null,后被{n: 2}的地址所覆盖。原{n: 1}对象被扩展成 {n: 1,x: [{n: 2}的内存地址]}

  7. 最后a.x为{n: 2}的x属性(因为我们到了下一条语句,重新计算了一次a的值),x属性没有被定义,所以是undefined。b.x中,b没有被覆盖,依然指向{n: 1}。只不过现在{n: 1}多了一个属性。现在的{n: 1}已经变成{n: 1,x: [{n: 2}的内存地址]}。所以b.x指向的是{n: 2}的内存地址。所以 b.x == {n: 2}


参考资料:

javascript 连等赋值问题 - SegmentFault

JS基础-连续赋值 - javascript - SegmentFault