JavaScript中的多重左侧赋值

221
var var1 = 1,
    var2 = 1,
    var3 = 1;

这等同于这样:

var var1 = var2 = var3 = 1;

我相当确定这是变量定义的顺序:var3,var2,var1,相当于以下代码:

var var3 = 1, var2 = var3, var1 = var2;

有没有办法在JavaScript中确认这一点?可能使用一些性能分析工具吗?


10
赋值运算符的结合方向是从右到左。更多JavaScript操作符的优先级和结合性请参考链接。 - neaumusic
1
如果我使用 this.var1 = this.var2 = this.var3 = 1,这个规则是否也适用? - Buddybear
是的,直到它成为全局变量,因为“this”指的是窗口对象。 - Bikram Kumar
8个回答

450

实际上,

var var1 = 1, var2 = 1, var3 = 1;

不等同于:

var var1 = var2 = var3 = 1;

区别在于作用域:

function good() {
  var var1 = 1, var2 = 1, var3 = 1;
}

function bad() {
  var var1 = var2 = var3 = 1;
}

good();
console.log(window.var2); // undefined

bad();
console.log(window.var2); // 1. Aggh!

实际上这表明赋值运算符是右结合的。 bad 示例等同于:

var var1 = (window.var2 = (window.var3 = 1));

54
当,这出乎意料。谢谢你的提醒,我会小心注意的。 - David Calhoun
4
我不明白...为什么bad()函数中的变量会在函数作用域之外?而且当函数执行完毕时,它们不应该被垃圾回收吗? - SkinnyG33k
10
@SkinnyG33k 因为这是从右到左解析,所以它会先解析最右边的元素。因此,var var1=var2 发生在 var3 = 1var2 = var3 之后。就像 var3=1; var2=var3; var var1=var2 - gcb
16
请注意:如果您事先知道要做这种事情,仍然可以将定义与赋值分开。因此:var v1,v2,v3; 然后稍后:v1 = v2 = v3 = 6; 它们仍将在本地范围内。由于David提到了警报,这将按预期工作(如果已经声明变量):alert(v1 = v2 = v3 = 6); - ShawnFumo
3
没错。但是如果我们遵循一些通用的最佳实践,比如在顶部声明变量,就可以避免不必要的错误,并避免局部变量泄漏到全局范围。参见:http://jsfiddle.net/gleezer/r9Mu8/1/ - Aurelio
显示剩余9条评论

27

在JavaScript中,赋值操作符是从右往左执行的。var var1 = var2 = var3 = 1;

如果这个语句执行后任何一个变量的值为1,那么逻辑上它肯定是从右侧开始赋值的。否则var1var2的值将为未定义。

你可以将其视为等同于var var1 = (var2 = (var3 = 1)); 其中最内层括号首先被计算。


1
谢谢,这确实有帮助。如果从其他方向进行评估(在这种情况下,错误将是var1 / var2未定义),考虑会抛出哪些错误会有所帮助。 - David Calhoun
5
这实际上是语法错误。在var后面不能立即跟着(。删除最外层的括号使其能够编译而不出错,即var var1 = (var2 = (var3 = 1));。当时我感觉这并没有很好地阐明问题,但我想它是一样的。 - Justin Johnson
var var1 = var2 = var3 = 1;.equal tovar var3 = 1; var var2 = var3; var var1 = var2; - xgqfrms

12

var var1 = 1, var2 = 1, var3 = 1;

在这种情况下,var关键字适用于这三个变量。

var var1 = 1,
    var2 = 1,
    var3 = 1;

这不等同于以下代码:

var var1 = var2 = var3 = 1;

在这种情况下,由于变量提升(hoisting),屏幕后台只有 var1 变量适用于 var 关键字,表达式的其余部分会正常评估,因此变量 var2, var3 变成了全局变量

Javascript 按照以下顺序处理此代码:

/*
var1 is local to the particular scope because of var keyword
var2 and var3 will become globals because they are used without var keyword
*/

var var1;   //only variable declarations will be hoisted.

var1 = var2 = var3 = 1; 

9
a = (b = 'string is truthy'); // b gets string; a gets b, which is a primitive (copy)
a = (b = { c: 'yes' }); // they point to the same object; a === b (not a copy)

(a && b)的逻辑等同于(a ? b : a),并且表现得像乘法(例如:!!a * !!b

(a || b)的逻辑等同于(a ? a : b),并且表现得像加法(例如:!!a + !!b

(a = 0, b)是不关心a是否为真值的简写方式,隐式地返回b


a = (b = 0) && "nope, but a is 0 and b is 0"; // b is falsey + order of operations
a = (b = "b is this string") && "a gets this string"; // b is truthy + order of ops

JavaScript 运算符优先级(操作次序)

请注意,逗号运算符实际上是最低权限的运算符,但括号是最高权限的运算符,在构建单行表达式时它们必须配合使用。


最终,您可能需要 'thunks' 而不是硬编码的值,对我来说,一个 thunk 既是函数又是结果值(同一件事情)。

const windowInnerHeight = () => 0.8 * window.innerHeight; // a thunk

windowInnerHeight(); // a thunk

4

试试这个:

var var1=42;
var var2;

alert(var2 = var1); //show result of assignment expression is assigned value
alert(var2); // show assignment did occur.

请注意第一个警告中的单个'='。这将显示赋值表达式的结果是分配的值,第二个警告将向您显示确实发生了分配。
逻辑上讲,分配必须从右到左链接。但是,由于这对JavaScript来说是原子性的(没有线程),因此特定的引擎可能会选择以稍微不同的方式进行优化。

1
谢谢你的答案。我想我正在寻找一种在保持多重赋值结构 (a=b=c) 的同时使用警示框的方法,但我认为这是不可能的。 - David Calhoun
1
像JavaScript中的这样的单个语句(尽管有几个表达式,但所有内容都归结为单个语句)可以被视为原子操作。你必须将其拆分开来。 - Joel Coehoorn

2
现在很明显,它们并不相同。编码方式为:

最初的回答

var var1, var2, var3
var1 = var2 = var3 = 1

那么,let赋值呢?与var完全相同,不要因为块作用域而让let赋值使你困惑。

最初的回答:

Let和var在赋值方面是一样的,不要被let的块级作用域所迷惑。

let var1 = var2 = 1 // here var2 belong to the global scope

我们可以这样做:

最初的回答:

let v1, v2, v3
v1 = v2 = v3 = 2

注意:顺便说一句,我不建议使用多个赋值,甚至不要在同一行中声明多个变量。最初的回答。

0

证明

let var1 = {set a(a){console.log(1)}},
    var2 = {set a(a){console.log(2)}},
    var3 = {set a(a){console.log(3)}};


var1.a = var2.a = var3.a = 1


-2

coffee-script可以轻松实现此功能。

for x in [ 'a', 'b', 'c' ] then "#{x}" : true

[ { a: true }, { b: true }, { c: true } ]

7
这并没有真正回答问题。请重新阅读问题。 - Martin
33
谁在乎CoffeeScript。 - neaumusic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接