sunmaobin.github.io icon indicating copy to clipboard operation
sunmaobin.github.io copied to clipboard

JS解惑-连等表达式

Open sunmaobin opened this issue 8 years ago • 0 comments

JS解惑-连等表达式

问题

如下3个表达式的区别:

//sample1
var str = 123;
var str1 = 123;
var str2 = 123;

//sample2
var str = 123,str1 = 123,str2 = 123;

//sample3
var str = str1 = str2 = 123;

答案


//`sample1` = `sample2`,区别仅仅是代码风格而已;

//sample2
var str = 123,str1 = 123,str2 = 123; //str,str1,str2 全部为局部变量

//sample3
var str = str1 = str2 = 123; //str 局部变量,str1,str2 为全局变量

最新补充于:2018年3月18日

关于连等表达式多啰嗦一些

连等表达式执行过程说明

  1. 先解析连等表达式,进行变量提升(hoisting)
    • 如果是局部变量,不存在则先定义
  2. 将连等式最后一个值,同时赋给前面的其它变量;
    • 如果最后一个值是对象,则是将这个对象先在内存中开辟一个位置(匿名),然后将这个指针指向前面的所有变量。

关于以上第1步的详细解释

比如:

var str=str1=str2=123;

解析过程如下:

  1. 先找到表达式中的变量:strstr1str2
  2. 进行变量提升,并定义:
    • var str,表示这是一个局部变量,则直接在当前执行函数中定义变量str,默认值:undefined

注意: str1str2,由于他俩前面并没有直接有 var 符号,但是又得为它们赋值,这时候JS引擎赋值时,就会把他们挂到全局对象 window 对象上,因为 window 对象已经存在,所以不会在定义了;而对象的属性,只有在赋值时,才会动态在堆内存中追加。所以,var1var2 也不会创建。

记住:变量提升创建的,只包含:基本类型、对象和声明的函数,不包含对象上的属性。

接下来就是一步步赋值的过程了,见下面第2步的解释。

关于以上第2步的详细解释

比如:

var str=str1=str2=123;

并不是: 将123先赋值给str2,再将str2赋值给str1,再将str1赋值给str; 而是: 将123赋值给str2,再将123赋值给str1,再将123赋值给str;

也就是上方的连等式可以理解为:

var str;
str = 123;
str1 = 123;
str2 = 123;

复杂示例

请大家给出如下表达式的执行结果:

var a = {n:1};  
var b = a;
a.x = a = {n:2};  
console.log('a.x=',a.x);//?
console.log('b.x=',b.x);//?

大家先自己给出一个答案,然后看看下面的分析跟你想的一样不?

详细分析

第一步:先将代码中的变量提升,不存在的变量先定义。

  1. 先找出以上代码片段中的所有变量
    • a
    • b
  2. 定义变量
    • var a:定义局部变量a,默认值 undefined
    • var b:定义局部变量b,默认值 undefined

于是代码片段变为:

//第一步做的事情
var a;  
var b;

//第二步开始的地方
a = {n:1}; 
b = a;

a.x = a = {n:2};  
console.log('a.x=',a.x);//?
console.log('b.x=',b.x);//?

第二步:一步步执行代码片段并赋值。

  1. a = {n:1} 将a赋值为一个对象 {n:1},这里发生了什么事情?

  2. b = a 将a对象赋值给b,我们知道,对象赋值其实就是指针的指向问题,就是b的指针也指向了a的值;

  3. a.x = a = {n:2},这一步我们按照上方的原理(并不是依次从右往左执行),把它拆解一下:

    • a.x = {n:2};
    • a = {n:2}
  4. 先看前一步,a.x = {n:2},其实就是在a的堆内存中,再额外增加一个属性x,并且指向新的对象,如下:

    • 执行完这一步,大家能看到,其实这时候:a 和 b 还是指向同一个对象,只是那个对象多了一个属性x而已。
    • 这时候:a.x = b.x 都等于 {n:2}
  5. 再看后一步,a = {n:2},就是将a的指针变化了,指向这个新的对象,如下:

    • 这时候:a = b.x 都等于 {n:2}(看蓝色的箭头指向同一个)
    • 而这时候a指针对应的对象中 {n:2},根本不存在x这个属性,所以 a.x=undefined;

最终答案

console.log('a.x=',a.x);//undefined
console.log('b.x=',b.x);//{n:2}

其实本题最容易绕晕的2个地方:

  1. 很多人把连等当成从右往左一个变量给另一个变量赋值!其实不是;
  2. 最后 {n:2} 是个新的对象,注意的地方是对象赋值,一定是一个新的地址了。

参考

(全文完)

sunmaobin avatar Nov 20 '17 08:11 sunmaobin