var a = { n: 1 };
var b = a;a.x = a = { n: 2 };
console.log(a.x); // --> undefined
console.log(b.x); // --> {n:2}
预热
关联性:
关联性决定了拥有相同优先级的运算符的执行顺序。
(a OP b) OP c
左关联既把左右的子表达式加上小括号,右关联同理。
赋值运算符:
- 赋值运算符是右关联
- 赋值运算符的返回结果就是赋值运算符右边的那个值
栗子:
a = b = 5;
b 被赋值为5,然后a也被赋值为b = 5 的返回值,也就是5,所以a b 都为5
成员属性运算符:
- 左关联
运算符优先级:
运算符的优先级决定了表达式中运算执行的先后顺序。
常用运算符优先级: 圆括号>成员属性>后置递增递减>逻辑非>前置递增、typeof>逻辑与/或>赋值
代码分析1:
var a = { n: 1 }; // 声明变量a,并在内存中创建了一个新对象,a指向这个新对象的地址
var b = a; // 声明变量b,并把a的地址赋值给变量b,所以b和a指向同个地址
代码分析2:
a.x = a = { n: 2};
-
因为成员属性运算符的运算优先级大于赋值运算符,所以先执行a.x(step1),但是a对象并没有x属性,所以a.x等于undefined并等待赋值运算,a还是指向旧地址#001
-
赋值运算符是右关联性的,所以执行a = { n: 2 }(step2),这时候a的地址发生了变化,指向了新地址#002,因为b还保留着a的旧地址,所以旧地址没被释放掉。
-
a.x = a = { n: 2 },可以理解为a.x被赋值为a = { n: 2 } 的返回值,既{ n: 2 }。第一个=号右边的a已经指向了新地址,而第一个等=号左边的a还是旧地址。因为先执行a.x(step1),这时候的a还是指向旧地址,然后等step2执行完之后执行a.x =
step2的返回值(step3)。
所以 a = { n : 2 }; b = { n: 1; x: { n: 2 } };
a.x = undefined;
b.x = { n: 2 };