JavaScript引用类型连续赋值问题

先来看下面这段代码:


var a = {n: 1};
var b = a;
a.x = a = {n: 2};  // 这条语句执行时,a.x仍然指向的是原来地址
console.log(a.x);  // undefined
console.log(b);    // {x: {n: 2},n: 1}

这个该怎么理解,我的理解是一条语句为结束a的地址就没有被改变,不知道这样正不正确?

阅读 5.2k
6 个回答

为了说明清晰,我们假设{n:1}这个对象用OBJ_N1表示,{n:2}对象用OBJ_N2表示
赋值规则:
先从左往右计算每一个赋值表达式的值;
然后在从右往左执行赋值操作,赋值给右边的操作数,同一个表达式不会计算多次

var a = {n: 1};
var b = a;
a.x = a = {n: 2};  // 这条语句执行时,a.x仍然指向的是原来地址
console.log(a.x);  // undefined
console.log(b);    // {x: {n: 2},n: 1}

分解:

var a = {n: 1};
var b = a;

定义变量a指向OBJ_N1对象
定义变量b,其指向变量a指向的地址信息,也就是OBJ_N1,那么此时有变量b,a同时指向OBJ_N1

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

问题提到的连续赋值操作:
先求值a.x,a,{n:2}
结果
a.x: 找到a变量,指向OBJ_N1,其中的属性x为一个并不存在的属性,其值为undefined;
a: a指向OBJ_N1;
{n:2}: {n:2}新建了一个对象OBJ_N2

接下来从右往左赋值:
1.a变量指向OBJ_N2这个对象,也就是a不再指向OBJ_N1,OBJ_N1只有b和它由关联;
a={n:2}的返回结果为OBJ_N2;
2.将OBJ_N2对象地址赋值给第1步得到的OBJ_N1对象的属性x;因为对象中没有x属性,按JS给对象属性的赋值规则将为对象新建一个属性x,并将OBJ_N2赋值给x。

这个表达式执行完毕后,
OBJ_N1与b关联,并且添加了一个属性x,这个x的值为OBJ_N2
OBJ_N2与a关联

所以a.x也就是OBJ_N2.x为undefined
b为OBJ_N1,其有一个属性x,值为OBJ_N2

执行以下代码,我们能看到这一点

a.y="123";
console.log(b.x.y);//123

如果

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

写成

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

会是怎样的表现呢?
按上面的分析步骤
a.x中的a为OBJ_N1,a.x的值为OBJ_N1,出现一个对象的属性指向自己的问题,将出现循环引用而不能释放内存的问题
a={n:2};执行后,a被指向OBJ_N2,但是OBJ_N1引用自身的问题依旧存在,但是没有其它外部变量引用它,是否还是会引起内存溢出不清楚,个人认为JS的GC机制会去回收的~~

console.log(a.x); // undefined
console.log(b); //{x: {n: 1,x:{n:1,x:{n:1,...}}},n: 1}

a.x = a = {n: 2}; // 这条语句执行时,a.x仍然指向的是原来地址
主要就这句,运算从右到左,在给a赋值后,a.x中的a还是指向{n:1},所以a.x就等于{n:2}。

自己瞎想的啊 楼主参考下 首先要注意这个运算符的顺序,赋值符号是优先级最低的,而.运算符是比它要高的,a.x = a = {n: 2};这句里面最先进行的运算应该就是a.x这个,此时a还是引用{n:1}这个对象,然后赋值运算时从右到左的,而且一个赋值表达式返回的值就是赋值符号右侧的值也就是说a={n:2}返回的是{n:2};分解下这个语句就是,({n:1}).x=(a={n:2});最后结果就是a最先引用的那个对象(同时也是b引用的对象),添加了个'x'属性,这个属性是一个指向{n:2}的引用,而a已经从原先的引用变成了对{n:2}的引用,b的引用没有变还是对{n:1}的引用,只是这个对象又添加了一个属性'x',这个问题关键是要搞清楚运算的优先级和运算顺序以及js中把对象赋值给变量只是在变量中保存对这个对象的引用,所有的操作都是落实在那个对象上的,而不是变量上。说的有点乱希望楼主可以看明白啊

clipboard.png
其中AAAFFF000和BBBFFF000是假设存入的16进制地址,不一定是叫这个名字,但是是16进制的

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
1 篇内容引用
推荐问题
宣传栏