非常有意思的前端开发面试题(附答案)

 

今天看到一道非常有意思的面试题,值得思考,因为它结合了变量赋值与运算符的知识点,代码如下:...





今天看到一道非常有意思的面试题,值得思考,因为它结合了变量赋值与运算符的知识点,代码如下:

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

分析如下:

假设有一句代码: A=B=C; ,赋值语句的执行顺序是从右至左,所以问题在于:

是猜想1: B = C; A = C;

还是猜想2: B = C; A = B;

我们都知道若两个对象同时指向一个对象,那么对这个对象的修改是同步的,如:

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

所以,连等赋值真正的运算规则是:B = C; A = B。

即连续赋值是从右至左永远只取等号右边的表达式结果赋值到等号左侧。

通过上面可以看到连续赋值的真正规则,那么再回归到文章开头的那个案例,如果按照上述规则将连续赋值拆开会发现结果不一样了,如:

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

所以连续赋值语句虽然是遵从从右至左依次赋值的规则但依然不能将语句拆开来写,至于为什么?

我猜测:js内部为了保证赋值语句的正确,会在一条赋值语句执行前,先把所有要赋值的引用地址取出一个副本,再依次赋值。

所以我认为这段代码 a.x=a={n:2}; 的逻辑是:

1、在执行前,会先将a和a.x中的a的引用地址都取出来,此值他们都指向{n:1};

2、在内存中创建一个新对象{n:2};

3、执行a={n:2},将a的引用从指向{n:1}改为指向新的{n:2};

4、执行a.x=a,此时a已经指向了新对象,而a.x因为在执行前保留了原引用,所以a.x的a依然指向原先的{n:1}对象,所以给原对象新增一个属性x,内容为{n:2}也就是现在a;

5、语句执行结束,原对象由{n:1}变成{n:1,x:{n:2}},而原对象因为无人再引用他,所以被GC回收,当前a指向新对象{n:2};

6、所以就有了文章开头的运行结果,再执行a.x,自然就是undefined了。

图解如下:




    关注 微文阅读推荐


微信扫一扫关注公众号

0 个评论

要回复文章请先登录注册