前言
在之前做练习时遇到了类似下面这道题的场景,发现输出结果和预期结果略有出入。本文对JS中的连等赋值做个简单讨论。
var a = b = c = 1;
function test(){
var a = b = c = 2;
console.log(a, b, c); // 2, 2, 2;
}
test();
console.log(a, b, c); // 1, 2, 2;
结论
var a = b = c = {value : 1};
// 等价于
var tmp = {value : 1};
var a = tmp;
b = tmp;
c = tmp;
两个探索 v1.0
-
变量声明命令
var
是否对连等赋值中的所有变量都有用?做个实验
function test(){ var a = b = c = 1; } test(); console.log(a); console.log(b); console.log(c);
var
声明的变量具有函数作用域,在函数test()
中声明的变量,在函数外部是访问不到的。预期结果一
如果var
对a b c
都有用,那么变量a b c
都是函数test()
的内部变量,此时打印变量a b c
都会报错未声明。预期结果二
如果var
只对a
有用,那么变量a
是函数test()
的内部变量,而变量b c
则会隐式地声明为window
对象的属性,即全局变量,此时打印变量a
会报错未定义,而打印b c
则会正常显示为1
。实验结果
// console.log(a); // a is not defined console.log(b); // 1 console.log(c); // 1
验证
我们同时试着打印一下window
对象中a b c
,发现b c
确实被声明成了全局变量。function test(){ var a = b = c = 1; } test(); console.log(window.a); // undefined console.log(window.b); // 1 console.log(window.c); // 1
-
连等赋值的实际赋值过程是什么样的?(内容有误,以改正内容为准)从赋值号
=
它本身的规则来讲,是从右向左运算的,将右边的值赋值给左边的变量。这么来考虑,其过程好像是很清晰的。即var a = b = c = 1; // 等价于 c = 1; b = c; a = b;
但有没有可能是这样下面的
var a = b = c = 1; // 等价于 c = 1; b = 1; a = 1;
做个实验
我们用对象{value : 1}
来代替1
.var a = b = c = { value : 1}; console.log(a === b); console.log(b === c); console.log(a === c);
我们知道对象之间进行想等比较时,比较的是两个对象的地址是否一致,也就是说只有变量指向同一个对象时,才返回
true
。预期结果一
如果是第一种赋值方式,那么三个变量都会指向同一个对象,结果应该为三个true
。预期结果二
如果是第二种赋值方式,那么三个变量各自会指向不同的对象,结果应该为三个false
。实验结果
var a = b = c = { value : 1}; console.log(a === b); // true; console.log(b === c); // true; console.log(a === c); // true;
两个改正 v1.1
-
赋值顺序
起初以为是从右向左依次赋值,但后来实践中推翻了这个猜测。实际上是从左向右。
做个实验
var a = { value : 1}; b = a; a.obj= a = { value : 2}; console.log(b);
预期结果一
如果是从右向左赋值(即先赋值a
再赋值a.obj
),此时a
指向了一个新的对象,那么对a.obj
进行赋值就不会影响b
,输出结果应该是{value:1}
。预期结果二
如果是从左向右赋值(即先赋值a.obj
再赋值a
),那么在对a.obj
进行赋值时,a
和b
指向的是同一个对象,那么输出结果的对象中会包含value
和obj
两个属性。实验结果
结果中显示有value
和obj
两个属性,则说明连等赋值的赋值顺序是从左向右。 -
赋值方式
同时因为赋值方向的确定,此前猜测的赋值方式也是错误的。在之前的猜测中,为了解释连等语句中
a = b = c = {value : 1}
,a b c
三个变量指向同一个对象。认为下一个变量是用上一个变量赋值的。
但实际上没有那么复杂,就是创建一个对象,然后依次让a b c
指向这个对象。
可以理解为其等价操作是:var tmp = {value: 1}; a = tmp; b = tmp; c = tmp;