js连续赋值及引用类型指针问题(a.x=a={n:2})

关于技术您现在的位置是:首页 > 关于技术

js连续赋值及引用类型指针问题(a.x=a={n:2})

头像 2021-03-30 18:09:09 401 人已围观 0 条评论

简介

面试题:(考察赋值表达式) a.x = a = { n: 2 };

最近看到的面试题:(考察赋值表达式)

下面代码会输出什么?

var a = { n: 1 };
var b = a;
a.x = a = { n: 2 };
console.log( a.x ) // undefined
console.log( b.x ) // Object { n: 2 }

正解:

下面来分析这段代码的工作步骤,从而进一步理解js引用类型“赋值”的工作方式。

首先

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

在这里a指向了一个对象{n: 1},b指向了a所指向的对象,也就是说,在这时候a和b都是指向对象{n: 1}的:

接着继续看关键代码行:

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

根据js引擎语法解析,会先去从左到右寻找有没有未声明的变量,如果有就把该变量提升至作用域顶部并声明该变量。

那么恭喜js引擎找到了a.x这个属性没有声明,于是乎在{n: 1}这个内存区声明一个x属性等待赋值。

从图上可以看到,由于b跟a一样是指向同一个对象的,要表示该对象的x属性除了用a.x,自然也可以使用b.x来表示。

语法解析完成之后,开始进行赋值运算,我们知道运算符的优先级决定了表达式中运算执行的先后顺序,优先级高的运算

符最先被执行。赋值运算符是从右往左的,不过由于“.”是优先级最高的运算符,所以这行代码先计算a.x,此时a.x属性还

没有被赋值它的值为undefined。

接下来开始依循“从右往左”的赋值运算顺序先执行a = { n: 2 },这时候,将a变量的指针指向了一个新的内存区,即对象

{n: 2},那么a变量就脱离了对内存区{n: 1}的引用关系。

但此时内存区{n: 1}并没有被GC回收,因为b变量的指针依然指向它。并且因为之前就声明了x属性,所以一开始js已经在

该内存区增加了x: undefined属性,由于赋值运算从右往左运算,所以在a.x = a = {n: 2}这个式子中,a.x最终被指向了{n:

2};

【可这样理解:在连续赋值的时候,各个左边的变量赋值都是同时的(没有顺序),执行的是赋值的瞬间哪个对象的

内存操作。比如a.x = {n: 2},此时的a对应的还是{n: 1}那个老的内存区;而a = {n: 2}仅仅是a变量而已,赋值完了之后才

脱离原来老的内存区,指向了新的内存区{n: 2}】

那么这时候结果就显而易见了,当console.log(a.x)的时候,a是指向对象{n: 2}的,但是对象{n: 2}没有x属性。于是js会向

上遍历原型链,当查找到原型链的最顶端 – 也就是Object.prototype – 仍然没有找到指定的属性时,自然也就输出

undefined;而在console.log(b.x)的时候,由于b指向的对象中存在x: {n: 2}属性,自然也就输出了Object {n: 2}了。

 

理解了么?我们再看一个例子:

var a = {x:{xx:1},y:2,z:3};
var b = a.x;
var c = a;
a.w = a.x.xx = a.y = a = {x:10,y:20};
console.log(a); // {x: 10, y: 20}
console.log(b); // {xx : {x: 10, y: 20}}
console.log(c); // {x:{xx:{x:10,y:20}},y:{x:10,y:20},z:3,w:{x:10,y:20}}

结合上个例子,及以下图解来简单分析:
首先

var a = {x:{xx:1},y:2,z:3};
var b = a.x;
var c = a;

然后关键代码

a.w = a.x.xx = a.y = a = {x:10,y:20};

参考:https://zhuanlan.zhihu.com/p/102085119

文章评论


  • 0 条评论来说两句吧…  (* 为必填项,邮箱不会公开)

  •  *
  •  *
  • 提交评论

最停留-个人博客

友情推荐

  • 微信公众号:扫描加关注
  • 最停留-微信公众号