var a = {n:1};
var b = a;
a.x = a = {n:2};
console.log(a.x);
console.log(b.x);
无意之中看到的题目,要求输出a.x和b.x的值?
首先先说一下答案,a.x为undefined;b.x为{n:2};
我这里用自己的语言整理一下答案, 首先a和b都指向{n:1}这个变量,我们知道在JavaScript中对象是存储在堆内存中,变量就是对象的引用地址。
这一步应该都很好理解,我画了一个图,将{n: 1}称为对象A。
这里是第一步的过程,
之后a.x = a ={n:2};这一点应该是让好多人难以理解的地方。
因为正常执行顺序应该是先赋值a = {n: 2}这一个语句,之后a.x = a。
这样理解是没有错的,不过忽略了最重要的一点,优先级。
给几个例子,简单举例一下
console.log(1 + 2 * 6); //13 console.log(2 * 2 ** 6); //128
这里可以参考MDN文档,"."运算符在JavaScript中的优先级仅次于"()",运算符优先级。
下面这个例子可以很好说明
var a = Object.defineProperty({}, 'f', { value: 456, writable: false, }); Object.freeze(a); var b = a.f = 789; console.log(b); //789 console.log(a.f); //456
这里我定义了变量a,且让他不可修改,如果没有优先级的话,a.f为456,b的值也应该为456。
回到第一个例子,a.x = a ={n:2}; a.x这里会被最先执行,a.x就相当于在对象A的堆内存中添加了一个属性
之后执行a = {n: 2},这里因为a的引用类型变更,导致变量a重新指向一个地址(对象B)。
之后执行a.x = a,这一步因为a.x在一开始就已经被执行了,当时a的值指向对象A,x是对象A的一个属性,后面a被修改指向对象B,所以就是将X的值重新赋值于对象B。
但是这时a的地址是指向对象B, 这也是为什么,一开始输出 console.log(a.x);是undefined的原因了,
因为a变量指向的变量B根本就没有x这个属性, 而输出console.log(b.x);指向一个对象{n: 2}的原因了。
最后给出一道题,试着解释一下为什么? a.x = a = {};
因为根据运算符规则,a.x最先被执行,a没有被声明为undefined,a.x自然就报错了。