菜鸡前端回复《友好"挑战"掘金全体前端》

1,847 阅读3分钟

写在前面

最近偶然逛掘金,看到了一篇讨论特别火的文章,主要问题如下

var a = {n: 1};

var b = a;  

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

console.log(a);
console.log(a.x)
console.log(b);
console.log(b.x);

输出的结果是什么?

相信知道结果的人不在少数,但是作为一个菜鸡前端开发来说,只是想做的或者说应该做的是在自己知识基础上尝试性的解释下这个问题,其他的并不敢妄断。如有解释不对的地方,希望各位指出,帮助我更加深入的理解

昨天跟公司的大佬也face to face交换了一下思路,发现自己要学的还真是特多的。

正文

首先说一下,我在工作中没有见到过这种写法(当然不排除,我的层次不足)。

程序员所生产的代码是给人看给机器执行的,这种写法有点反人类,并不是那么容易维护,review的时候很痛苦,想在几百上千行中注意到这样的语句还是比较麻烦的。

在我的理解中这个更像一个考题,来考察面试者的知识点。那既然说到了知识点,我们言归正传好了,来说说这个题目。

JS中基础类型和引用类型

下面来说说这两种类型的存储

栈内存(stack)
var a = 1 

基础数据类型存储在栈内存中

如上,定义一个变量a,系统自动分配存储空间(栈内存)。按值访问,因此我们可以直接操作保存在栈内存中的值。

堆内存(heap)
var a = { n : 1 }

需要明确的是引用数据类型的值存储在堆内存中。上面我们生成的变量a 其实保存在栈中, a的值就是指向堆中{n:1}的内存地址

有了这些基础我们把问题拆解开:

第一部分

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

忽略难看的因素

实际上是将栈中a存储的堆内存地址赋值给了b。

第二部分

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

这部分需要注意的是优先级

'.'的优先级大于赋值,所以最先执行的是a.x,再执行赋值操作,赋值操作是右结合的,所以如下:

最先执行的a.x可以看做是 a.x = undefined;

然后进行赋值操作, 但是需要注意,因为先执行的a.x = undefined;,a.x中的a已经是对堆中对象{n:1,x:undefined}的引用

a={n:2}

将栈中保存的a变量指向新的引用类型

忽略难看手稿

然后是

a.x = a;

前面已经说过了,由于优先级的原因a.x中的a已经完成了对堆内存中对象的引用,指向的是{n:1,x:undefined}(地址是0x6789),并不是更改之后a的值(0x8889), 赋值操作可以变形为 b.x = a;

所以输出结果

写在最后

文章有粗陋浅薄之处,请各位大神斧正

我觉得提出疑问大家谈论没太大的问题,毕竟掘金是大家交流的地方,也有很多优秀大佬愿意帮助别人。

更重要的应该是关注问题的本身和问题背后隐藏的问题,提高自己、帮助他人。不要太在意其他东西,有些东西自己明白就好了,永远无法叫醒一个装睡的人,不是吗?

掘金会越办越好的,风气也会越来越好。大家加油