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

This is equivalent to this:

var var1 = var2 = var3 = 1;

I'm fairly certain this is the order the variables are defined: var3, var2, var1, which would be equivalent to this:

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

Is there any way to confirm this in JavaScript? Using some profiler possibly?

3
  • 11
    ASSIGNMENT HAPPENS RIGHT TO LEFT javascript operator precedence Commented Dec 2, 2015 at 23:45
  • 1
    is this also applicable if I use this.var1 = this.var2 = this.var3 = 1 ? Commented Oct 29, 2018 at 13:07
  • Yes, untill it is global variable because this refers to the window object. Commented Jun 2, 2021 at 9:26

8 Answers 8

454

Actually,

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

is not equivalent to:

var var1 = var2 = var3 = 1;

The difference is in scoping:

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!

Actually this shows that assignment are right associative. The bad example is equivalent to:

var var1 = (window.var2 = (window.var3 = 1));
Sign up to request clarification or add additional context in comments.

14 Comments

Dang, that's unexpected. Thanks for the tip, I'll watch out for that.
I don't understand... why would the variables in bad() be outside the functions scope? And shouldn't they be garbage collected when the function is finished?
@SkinnyG33k because it's right to left. so it will parse the right most before the left most. so var var1=var2 happens after var3 = 1 and after var2 = var3. it's like var3=1; var2=var3; var var1=var2
Just to note: if you know you want to do this kind of thing ahead of time, you could still break up the definition from the assignment. So: var v1, v2, v3; Then later on: v1 = v2 = v3 = 6; They'll still be in local scope. Since David mentioned alerts, this would work as expected (if pre-var'd): alert(v1 = v2 = v3 = 6);
Exactly. But if we follow some common best practices, in this case by declaring our variables at the top we can keep from unwanted mistakes and avoid local variables leaking to the global scope. See: jsfiddle.net/gleezer/r9Mu8/1
|
27

Assignment in javascript works from right to left. var var1 = var2 = var3 = 1;.

If the value of any of these variables is 1 after this statement, then logically it must have started from the right, otherwise the value or var1 and var2 would be undefined.

You can think of it as equivalent to var var1 = (var2 = (var3 = 1)); where the inner-most set of parenthesis is evaluated first.

3 Comments

Thanks, this definitely helps. It helps to think in terms of what errors would be thrown if it were evaluated other than right-to-left (in this case, the error would be that var1/var2 are undefined).
It's actually a syntax error. You can not have ( immediately after var. Removing the outer set of parenthesis allows it to compile without error, var var1 = (var2 = (var3 = 1));. At the time I felt that it didn't illustrate the point quite as well, but I suppose its the same.
var var1 = var2 = var3 = 1;. equal to var var3 = 1; var var2 = var3; var var1 = var2;
14

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

In this case var keyword is applicable to all the three variables.

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

which is not equivalent to this:

var var1 = var2 = var3 = 1;

In this case behind the screens var keyword is only applicable to var1 due to variable hoisting and rest of the expression is evaluated normally so the variables var2, var3 are becoming globals

Javascript treats this code in this order:

/*
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; 

Comments

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) is logically (a ? b : a) and behaves like multiplication (eg. !!a * !!b)

(a || b) is logically (a ? a : b) and behaves like addition (eg. !!a + !!b)

(a = 0, b) is short for not caring if a is truthy, implicitly return 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 Operator Precedence (Order of Operations)

Note that the comma operator is actually the least privileged operator, but parenthesis are the most privileged, and they go hand-in-hand when constructing one-line expressions.


Eventually, you may need 'thunks' rather than hardcoded values, and to me, a thunk is both the function and the resultant value (the same 'thing').

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

windowInnerHeight(); // a thunk

Comments

4

Try this:

var var1=42;
var var2;

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

Note the single '=' in the first alert. This will show that the result of an assignment expression is the assigned value, and the 2nd alert will show you that assignment did occur.

It follows logically that assignment must have chained from right to left. However, since this is all atomic to the javascript (there's no threading) a particular engine may choose to actually optimize it a little differently.

2 Comments

Thanks for the answer. I think I was looking for a way to use the alerts while still maintaining the multiple-assignment structure (a=b=c), but I don't think that's possible.
Individual statements like that in javascript (and, though several expressions, that all works out to a single statement) can be considered atomic. You'd have to break it up.
2

It is clear by now, that they are not the same. The way to code that is

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

And, what about let assigment? Exactly the same as var, don't let the let assigment confuse you because of block scope.

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

We could do the following:

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

Note: btw, I do not recommend use multiple assignments, not even multiple declarations in the same line.

Comments

0

PROOF

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

Comments

-2

coffee-script can accomplish this with aplomb..

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

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

2 Comments

This does not really answer the question. Please re-read the question.
who cares about coffeescript

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.