var a = {x:1};
var b = a;
a.x = a = {n:1};
console.log(a)
consoel.log(b)
首先来看这道题想考察什么: 1、JS类型的存放。2、运算符的执优先级
一、JS类型的存放
JS类型共有两种:
- 基本类型 (primitive values) - 包括Undefined, Null, Boolean, Number和String五种基本数据类型
- 引用类型 (reference values) - 保存在内存中的对象们,不能直接操作,只能通过保存在变量中的地址引用对其进行操作
JS的两种类型是存放在不同的地方的,
- 基本类型存放在栈内存里,通过按值传递。

- 引用类型放在堆内存里,按引用传递。指的是,在堆内存里开辟一块空间,把内容放进去,同时把堆内存的地址赋值给栈里的变量。

二、运算符的执优先级



综上,来看这道题
var a = {x:1};
/*定义a,a赋值为`{x:1}`;
为a在内存堆中分配一块内存用于存储`{x:1}`,假设其地址为add_1;(蓝色箭头)
此时add_1引用计数为1,即a,内容为`{n:1}`。*/
var b = a;
/*定义b,b赋值a,add_1被b引用。(蓝色箭头)
此时add_1引用计数为2,即a和b,内容为`{n:1}`。*/
a.x = a = {n:1};
/*(`=`赋值运算符:关联性为从右向左,优先级为3。`.`成员访问运算符:关联性为从左向右,优先级为19。19>3,所以先计算成员访问运算符)
(1):a.x是成员访问运算表达式,所以add_1中的x赋值为`a = {n:1}`的返回值`{n:1}`。该返回值就是a被赋值的内容即(2),
add_1被改写`{x:{n:1}}`。(右侧黄色箭头)
此时add_1引用计数为2,即a、b,内容为`{x:{n:1}}`。
(2):a赋值为`{n:1}`;
为a在内存堆中分配一块内存用于存储`{n:1}`,假设其地址为add_2; (左侧黄色箭头)
此时add_1引用计数为1,即b,内容为`{x:{n:1}}`。
此时add_2引用计数为1,即a,内容为`{n:1}`。*/
console.log(a);
/*现在a的存储地址add_2,内容为{n:1}。*/
console.log(b);
/*现在b的存储地址add_1,内容为{x:{n:1}},所以b为{x:{n:1}}*/

有一道类似的题:
var a = {n:1};
var b = a; // 持有a,以回查
a.x = a = {n:2};
alert(a.x);// --> undefined
alert(b.x);// --> {n:2}
alert(b); // -->{x:{n:2},n:1}
alert(a); // -->{n:2}
道理类似,只不过因为x在原来的add_1中不存在,就会先声明,后赋值。