变量赋值问题

298 阅读2分钟
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中不存在,就会先声明,后赋值。