221
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?

David Calhoun
  • 8,315
  • 4
  • 30
  • 23

8 Answers8

450

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));
Jonathan
  • 2,700
  • 4
  • 23
  • 41
Crescent Fresh
  • 115,249
  • 25
  • 154
  • 140
  • 54
    Dang, that's unexpected. Thanks for the tip, I'll watch out for that. – David Calhoun Nov 19 '09 at 03:43
  • 3
    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 Jan 20 '13 at 16:23
  • 10
    @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` – gcb Jan 29 '13 at 18:51
  • 16
    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);` – ShawnFumo Sep 10 '13 at 20:11
  • 3
    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: http://jsfiddle.net/gleezer/r9Mu8/1/ – Aurelio Jun 13 '14 at 12:36
  • @Nobita I was just about to post the same link. It should be brought up. http://jsfiddle.net/wLwyajy2/ – Rohit Oct 30 '14 at 16:19
  • 1
    "Dang, that's unexpected." Why would this be unexpected? Most languages require you to declare your variables before usage. JavaScript is no different, if you neglect to declare your variable it defaults to the global window object. Start using 'use strict' in your javascript and you will become a better JavaScript programmer. – cchamberlain Mar 31 '15 at 05:06
  • So the 'var' keyword is applying to var1 and rest of the variables are simply becoming globals ... :O – Gangadhar Jannu Mar 14 '16 at 09:25
  • 1
    What happens if what you're assigning to isn't a variable, but instead a property of an object? Is scoping an issue, then? – mbomb007 Mar 19 '18 at 19:39
  • @mbomb007: what do you mean, `obj.foo = var2 = var3 = ...` or `obj.foo = obj.bar = obj.baz = ...` or what? – Crescent Fresh Mar 19 '18 at 20:15
  • The 2nd one, with all of them being properties of the same object. – mbomb007 Mar 19 '18 at 20:24
  • 1
    @mbomb007: `obj.foo = obj.bar = obj.baz = ...` will *not* introduce globals. `obj` is the explicit scope in that case, not `window`. – Crescent Fresh Mar 21 '18 at 14:37
  • global scope & function local scope & let / const block scoped – xgqfrms Aug 19 '19 at 06:28
  • ^ what he said. Use `let` keyword instead of var. That being said, if you need backwards compatibility, you will need to transpile to ES5. – OzzyTheGiant Jul 07 '20 at 17:29
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.

Antony
  • 1,253
  • 11
  • 19
Justin Johnson
  • 30,978
  • 7
  • 65
  • 89
  • 1
    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). – David Calhoun Nov 19 '09 at 03:48
  • 5
    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. – Justin Johnson Nov 19 '09 at 17:06
  • `var var1 = var2 = var3 = 1;.` equal to `var var3 = 1; var var2 = var3; var var1 = var2;` – xgqfrms Aug 19 '19 at 06:31
11

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; 
Gangadhar Jannu
  • 4,136
  • 6
  • 29
  • 49
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
neaumusic
  • 10,027
  • 9
  • 55
  • 83
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.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
  • 1
    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. – David Calhoun Nov 19 '09 at 03:56
  • 1
    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. – Joel Coehoorn Nov 19 '09 at 03:57
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.

fender0ne
  • 281
  • 4
  • 13
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
FLAW
  • 307
  • 2
  • 12
-2

coffee-script can accomplish this with aplomb..

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

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

Alex Gray
  • 16,007
  • 9
  • 96
  • 118