sunmaobin.github.io
sunmaobin.github.io copied to clipboard
JS解惑-连等表达式
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日
关于连等表达式多啰嗦一些
连等表达式执行过程说明
- 先解析连等表达式,进行变量提升(hoisting)
- 如果是局部变量,不存在则先定义
- 将连等式最后一个值,同时赋给前面的其它变量;
- 如果最后一个值是对象,则是将这个对象先在内存中开辟一个位置(匿名),然后将这个指针指向前面的所有变量。
关于以上第1步的详细解释
比如:
var str=str1=str2=123;
解析过程如下:
- 先找到表达式中的变量:
str、str1、str2; - 进行变量提升,并定义:
-
var str,表示这是一个局部变量,则直接在当前执行函数中定义变量str,默认值:undefined;
-
注意: str1 和 str2,由于他俩前面并没有直接有 var 符号,但是又得为它们赋值,这时候JS引擎赋值时,就会把他们挂到全局对象 window 对象上,因为 window 对象已经存在,所以不会在定义了;而对象的属性,只有在赋值时,才会动态在堆内存中追加。所以,var1 和 var2 也不会创建。
记住:变量提升创建的,只包含:基本类型、对象和声明的函数,不包含对象上的属性。
接下来就是一步步赋值的过程了,见下面第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);//?
大家先自己给出一个答案,然后看看下面的分析跟你想的一样不?
详细分析
第一步:先将代码中的变量提升,不存在的变量先定义。
- 先找出以上代码片段中的所有变量
- a
- b
- 定义变量
-
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);//?
第二步:一步步执行代码片段并赋值。
-
a = {n:1}将a赋值为一个对象{n:1},这里发生了什么事情?
-
b = a将a对象赋值给b,我们知道,对象赋值其实就是指针的指向问题,就是b的指针也指向了a的值;
-
a.x = a = {n:2},这一步我们按照上方的原理(并不是依次从右往左执行),把它拆解一下:-
a.x = {n:2}; -
a = {n:2}
-
-
先看前一步,
a.x = {n:2},其实就是在a的堆内存中,再额外增加一个属性x,并且指向新的对象,如下:
- 执行完这一步,大家能看到,其实这时候:a 和 b 还是指向同一个对象,只是那个对象多了一个属性x而已。
- 这时候:a.x = b.x 都等于 {n:2}
-
再看后一步,
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个地方:
- 很多人把连等当成从右往左一个变量给另一个变量赋值!其实不是;
- 最后
{n:2}是个新的对象,注意的地方是对象赋值,一定是一个新的地址了。
参考
(全文完)