JS学习笔记——一道有趣的JavaScript连等=赋值面试题

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、猜想二

注意:.运算优先=赋值运算

因此此处赋值可理解为:

  1. 声明变量aa的指针指向地址为{n:1}
  2. 声明变量bb的指针指向也为地址{n:1}
  3. .运算优先于=赋值运算,所以先执行.运算,声明a对象中的x属性,用于赋值,此时b仍然指向a的地址,同时拥有未赋值的x属性,a和b此时为{n:1 , x:undefined}
  4. 执行=赋值运算,对a对象赋值,此时变量名a改变指向到对象{n:2}
  5. 执行a.x=a的操作,因为在第三步a.x的指针已经创建,所以直接将a.x的指针指向{n:2}即可
  6. b的指针依旧指向原来地址,即{n:1,x:{n:2}}

(控制台打印)
JS学习笔记——一道有趣的JavaScript连等=赋值面试题_第1张图片
所以,猜想二这种解法是正确的,同时在这个过程中,我们始终要明白:

变量被赋值指针发生改变的时候

  • 如果已有指针,那么不改变它
  • 如果没有指针,即那个变量还没被申明,那么就创建它,指向 undefined

在上面的案例中:

  • a.x没有指针的,所以创建它,指向 undefined
  • a有指针的,指向 {n:1}
  • 后面找到的指针,都指向最右侧赋的那个值,即{n:2}

所以执行以后,就有了如下的变量关系图
JS学习笔记——一道有趣的JavaScript连等=赋值面试题_第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 连等赋值问题
  • 千万不要在JS中使用连等赋值操作

你可能感兴趣的:(javascript,javascript,前端,es6)