Multiple left-hand assignment with JavaScript

JavascriptVariablesVariable Assignment

Javascript Problem Overview


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?

Javascript Solutions


Solution 1 - Javascript

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));

Solution 2 - Javascript

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.

Solution 3 - Javascript

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

Solution 4 - Javascript

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

Solution 5 - Javascript

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.

Solution 6 - Javascript

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.

Solution 7 - Javascript

coffee-script can accomplish this with aplomb..

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

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDavid CalhounView Question on Stackoverflow
Solution 1 - JavascriptCrescent FreshView Answer on Stackoverflow
Solution 2 - JavascriptJustin JohnsonView Answer on Stackoverflow
Solution 3 - JavascriptBuddybearView Answer on Stackoverflow
Solution 4 - JavascriptneaumusicView Answer on Stackoverflow
Solution 5 - JavascriptJoel CoehoornView Answer on Stackoverflow
Solution 6 - JavascriptfenderOneView Answer on Stackoverflow
Solution 7 - JavascriptAlex GrayView Answer on Stackoverflow