关于一道面试题的疑惑?

var obj = {
    a: 1
};
obj.b = obj = {
    c: 2
};
console.log(obj.b);//undefined

obj.b 为何输出undefined ?

阅读 3.2k
8 个回答

其实这个东西这么解释会清楚点:

.的优先级是高于=的,所以整个等式先计算.的运算

根据上面,所以整个等式第一步是先添加一个b的地址,等式大概变成这个样子[obj.b的地址]=obj={c:2}

=是从右向左运算的,而且是把=号右边的那个赋值给左边的

所以,变形后的等式运算时分为两步obj={c:2},然后[obj.b的地址]=obj

由于第一步的时候,obj已经指向新的地址,所以和[obj.b的地址]中的obj已经不是同一个。

所以,第二步的时候,[obj.b的地址]=obj是把新的obj赋值给原本obj.b的地址

所以才会出现obj输出{c:2}的情况。

更清晰一点,看看一个代码:

var obj = {
    a: 1
};
var obj2 = obj;
obj.b = obj = {
    c: 2
};
console.log(obj); // {c:2}
console.log(obj2); // { a:1, b:obj }
obj.b = obj = {c:2}

这句话可以理解成:先进行 obj = {c:2},再进行 obj.b = obj。

但这里是单语句,真正的赋值结果的保存是在语句执行完之后

所以这里,obj.b 还是在操作 {a:1},而 obj = {c:2} 则是让obj指向了一个新对象

执行之后,原对象变成 {a:1, b: {c:2}},但obj已经不指向它了,obj指向了{c:2}

所以 obj.b 当然就是undefined

新手上路,请多包涵
var obj = {
    a: 1
};
x = obj = {
    c: 2
};
console.log(obj.b);//undefined

你把上面的 obj.b 改成 x 再想。

赋值操作符 “=” 永远从等式的右边往左边赋值。你从这样的方向再看一遍

这个很容易理解啊,其实就考量的运算符优先级和GC
下面我们深入浅出去探究这个问题,如果看不懂的,欢迎跟帖咨询。
我们把上面的代码改下:

var obj = {
    a: 1
};
obj.b = obj = {
    c: 2
};

此时能正确的输出2.

当连等的时候,会从右往左依次执行。

var obj = {
    a: 1
};

假如此时obj的对象地址为0x12341234,当执行下面一句

obj={
   c:2
};

时,obj又重新申请了一块内存用于存放新的对象,0x12345678
此时,gc会释放掉原来的对象内存即0x12341234
接下来

obj.b=obj;

注意,这两个obj是不一样的,前一个obj的地址为0x12341234,后一个为新申请的内存地址为0x12345678
然而前一个内存已经不存在了,对其操作会出错,当然,js的容错机制已经拦截了这个错误,并没有体现出来。也就是说,这是一个无意义的指令。
所以最后的结果是

Object {c: 2}

也就是说,最后的这个对象只有一个成员,就是cconsole.log(obj.b)当然是未定义的。

断点测试。有图有真相:

clipboard.png

clipboard.png

clipboard.png

clipboard.png

个人认为,对于javascript,连续赋值是这样的:
a=b=c等价于 a=b;b=c
这样也符合

赋值操作符 “=” 永远从等式的右边往左边赋值

@qfkobe24 @zkimyes

补充一个图:

clipboard.png

很多时候,chrome就是强大的工具,哈

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