Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

js中的 连续的赋值引发的血案 #5

Open
wohaiwo opened this issue Mar 23, 2017 · 0 comments
Open

js中的 连续的赋值引发的血案 #5

wohaiwo opened this issue Mar 23, 2017 · 0 comments

Comments

@wohaiwo
Copy link
Owner

wohaiwo commented Mar 23, 2017

话不多说,先上一道面试题

以下代码, 分别输出什么?

问题1:
var a = {n:1}; 
var b = a;  
a = {n:2}; 
a.x = a ;
console.log(a.x);
console.log(b.x);
问题2:
var a = {n:1}; 
var b = a;  
a.x = a = {n:2}; 
console.log(a.x);
console.log(b.x);

滴答滴答滴答....
过去一根烟的时间,少年想出来了没有?实在不行打开f12跑跑看

我准备开始来解释一波了

问题1:
a.x    // => {n:1, a: Object}
b.x    // => undefined

问题2:
a.x   // => undefined 
b.x   // => {n: 2}

这两道题考察的是

  • 引用类型是对象的话 就是内存地址的引用
  • 运算符的优先级 . > =
问题1中
var a = {n: 1}; 
// 由于a是一个对象,使用b引用的只是a对象的一个内存地址
var b = a;
// 此时a重新指向一个新的内存地址,存储了{n:2}的对象
a = {n: 2};
// 由于.的运算符优先级高于=
// 这里会先执行 a.x的操作,会在a对象里面添加一个x属性,然后在进行对a对象的赋值,会得到 a = { n: 1, x: a} 
// 这里会发生一直嵌套下去的对象
a.x = a;
console.log(a.x)     // {n:1, x: Object}
console.log(b.x)     // 由于这里b对象还是指向{n:1}, 所以输出 undefined
问题2中 让我们直接跳过前面两条语句
// 由于赋值语句都是从右到左的,但是这里会有点不同
// js在解析连续的赋值语句的时候 会将a.x和a中的a同时提取出来保存在内存中,此时a都是指向{n:1}  
// 然后进行 a = {n:2}的赋值操作,内存中的a就指向了新的一个内存地址
// 接着 a.x还是会先在原先保存的{n:1}插入一个新的x属性(但是此时a的引用的对象已经变为{n:2}),
// 即*n:1, x:{n:2}}  而原先b引用的内存地址在还是指向 {n:1, x:{n:2}} 来
a.x = a = {n:2};
console.log(a.x)	// undefined
console.log(b.x)    // {n:2}

让我们在看看下面这道题,看看输出了什么?

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

我猜你肯定不假思索的回答输出undefined, 但是上面三条语句经历一次内存回收 你知道吗?
让我慢慢跟你分析分析

之前我们说a.x和a中的a引用都是提取出来,然后暂时保存在内存中 当进行了a.x = a的赋值操作之后之前的原对象a指向了{n:1, x:{n:2}}对象,而原对象因为无人再引用他,所以被GC回收 只剩下a指向新对象**{n:2}**

但是为什么问题2中的b.x还能指向{n:2}, 这是因为一开始b = a中b就引用a的对象地址,当经过连续赋值操作中,由于原对象**{n:1, x:{n:2}}**一直才是被b在引用着,所以内存没有回收掉

通过下面这个例子来证明一下

var a = {n:1};
var b = a;
a.x = a = {n:2};
// b.x 和 a 现在都是引用都是同一块地址
console.log(a === b.x);  //true

以上 尽量少使用连续赋值来实现快速赋值操作,不紧可能会造成隐藏全局对象的产生,还可能会导致其他的问题出现
哦,对了 在严格模式'use strict'下面, var a = b = c = 1 会报错, 因为产生了 b,c两个全局变量

参考文章
js引用相关题目
谈谈javascript中使用连等赋值操作带来的问题

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant