1、面试题
今天无意中在网上看到一道面试题,据说是阿里的(我也无从考证),题目如下
var a = {n: 1}
var b = a
a.x = a = {n: 2}
console.log(a.n, b.n)
console.log(a.x, b.x)
先说答案
a.n = 2
b.n = 1
a.x = undefined
b.x = {n: 2}
不出所料,我答错了,于是便上网找解析,看了好多文章,感觉猜想和说法都是五花八门,我也是捉摸了好久,才理解过来。
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}
所以可以根据这个特性来测试连续赋值的顺序。
猜想1:
把C换成具体的对象,可以看到对a的修改不会同步到b上,因为在执行第一行和第二行时分别创建了两个 {n:1} 对象。如:
var b={n:1};
var a={n:1};
a.n=0;
console.log(b); //Object {n: 1}
猜想2:
把C换成具体的对象,可以看到对a的修改同步到了b,因为a和b同时引用了一个对象,如:
var b={n:1};
var a=b;
a.n=0;
console.log(b); //Object {n: 0}
测试真正的连等赋值:
var a,b;
a=b={n:1};
a.n=0;
console.log(b); //Object {n: 0}
可以看到是符合猜想2的
所以,连等赋值真正的运算规则是 B = C; A = B ,即连续赋值:是从右至左永远只取等号右边的表达式结果赋值到等号左侧
3、关于面试题的猜想
3.1、猜想一
按照从右往左顺序赋值考虑,对于a.x = a = {n:2},按常规思路应该是:
- 先把
{n:2}赋值给a - 然后再
创建 a.x,将{n:2}再赋值给a.x
按照这种说法,a.x 确实是被赋值为{n:2}。可是事实上,a.x 的值却是 undefined。
所以很明显,猜想一这种解法是有错误的,我们不能忽视.运算符和=运算符的优先级问题
3.2、猜想二
注意:.运算优先于=赋值运算
因此此处赋值可理解为:
- 声明
变量a,a的指针指向地址为{n:1} - 声明
变量b,b的指针指向也为地址{n:1} .运算优先于=赋值运算,所以先执行.运算,声明a对象中的x属性,用于赋值,此时b仍然指向a的地址,同时拥有未赋值的x属性,a和b此时为{n:1 , x:undefined}- 执行
=赋值运算,对a对象赋值,此时变量名a改变指向到对象{n:2} - 执行
a.x=a的操作,因为在第三步a.x的指针已经创建,所以直接将a.x的指针指向{n:2}即可 - b的指针依旧指向原来地址,即
{n:1,x:{n:2}}
(控制台打印)

所以,猜想二这种解法是正确的,同时在这个过程中,我们始终要明白:
在变量被赋值,指针发生改变的时候
- 如果
已有指针,那么不改变它 - 如果
没有指针,即那个变量还没被申明,那么就创建它,指向undefined。
在上面的案例中:
a.x是没有指针的,所以创建它,指向undefineda是有指针的,指向 {n:1}- 后面找到的指针,都指向最右侧赋的那个值,即
{n:2}
所以执行以后,就有了如下的变量关系图

大家可以参考这张图,慢慢理解。
4、延伸
如果理解上面的解法,那么下面这几道题思路解法也差不多
var a = {n: 1}
var b = a
a = a.x = {n: 2}
console.log(a)
console.log(b)
var a = {n: 1}
var b = a
a = {n: 2}
a.x = a
console.log(a)
console.log(b)
本篇博客参考:
本文探讨了一道关于JavaScript连等赋值的面试题,解析了其执行顺序和对象属性赋值的细节。通过猜想和实际测试,揭示了连等赋值从右至左的执行规则,并解释了在遇到.运算符时,.运算优先于=赋值运算。此外,还提供了相关问题的解题思路,帮助理解JavaScript中这一常见但易混淆的概念。
823

被折叠的 条评论
为什么被折叠?



