JS中的连等赋值操作

金三银四正是面试的好时候,有不少学员面试后在前端群里分享 JS 面试题,我正巧没事儿翻到一题做做看,发现答案与我自己的预期大相径庭,当时我就震惊了,在 chrome 控制台打印了下结果,还真是我错了。没错,就是下面这道连等赋值题:

1
2
3
4
5
var a = {
name: 'a'
};

a.x = a = {};

问:此刻的 a.x 是多少。

当时我简单的分析了下,由于 a 赋值给了一个新对象,接着又把 a 赋值给了 a.x ,那理所当然 a.x 不就是 {} 嘛。然而答案却是出乎意料的 undefined …

想了半天还是感觉理解不了,我就 google 了下,发现了这篇文章:千万不要在 JS 中使用连等赋值操作 。看完后理解了。

这道题的核心在于知道 JS 是如何执行 a.x = a = {} 这行代码的,分两步:一是确定 a 是什么,二是代码执行顺序是从右向左的。

我们一步步看,第一行代码 var a = {name: 'a'} ,这句话应该都没什么疑问,我们把 a 的地址假设为 AAA 。

然后就是 a.x = a = {} ,按照步骤来,先确定 a 是什么,在还没有赋值操作前,a.x 的 a 指向 AAA,中间的 a 也是指向 AAA ,新创建的对象 {} 地址假设为 BBB 。然后代码从右向左执行,a = {} ,所以中间的 a 指向了新地址 BBB ;接着 a.x = a ,此刻的 a.x 的 a 仍然是 AAA(因为在赋值前就已经确定了 a 的地址),赋值后原地址 AAA 的对象就变成了 {name: ‘a’, x: {}} 这里的 x 指向的就是新对象地址 BBB 。

上述操作结束后再来问 a.x 的值是什么,此刻的 a 已经在 a = {} 这一步赋值操作后指向了新的地址 BBB ,所以此刻的 a 是空对象 {} ,而空对象是没有 x 属性的,所以输出 undefined 。

是不是有点绕?这种题出出来真是挺看 JS 功底的,它考察了你对 JS 编译原理的理解与掌握情况。借用上面博客里博主的一句话作为收尾:尽量不要使用 JS 的连续赋值操作,除非真的了解它的内部机制及可能会产生的后果。

阅读更多

https://segmentfault.com/q/1010000002637728

可视化地址

http://pythontutor.com/visualize.html#mode=display

代码

1
2
3
4
5
6
7
8
9
10
let a = {
n: 1
};
let b = a;
a = a.x = {
n: 2
};

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