JSLint changes to the var statement

Douglas Crockford has changed the way that multiple variables are defined.

Previously, a comma-separated list was considered to be the correct way to define multiple variables:

var foo = "Foo",
    bar = "Bar";
// Invalid - results in the following error: Expected ';' and instead saw ','.

JsLint.com now considers the above to be incorrect.
It can still accept the comma-separated list though when you use the multivar declaration:

/*jslint multivar */
var foo = "Foo",
    bar = "Bar";

The recent change to how JSLint.com handles variables, now requires that each variable is to be defined separately.
I suspect that this is to make refactoring your code easier to achieve.

var foo = "Foo";
var bar = "Bar";

When asked about this, Crockford said in a recent discussion:

For anybody that wants a way to automatically convert from the list format to an each-line format, Pretty Diff has a varword setting that can help you to automatically convert from one way to another.

3 Likes

I have always written it as:

var foo, bar;
foo = "Foo";
bar = "Bar";

presumably this will now both fail jslint AND cannot be automatically converted.

I still think this way of doing the declaration is cleaner than either of the other two alternatives so I guess I’ll be specifying multivar whenever I use jslint in future (or simply ignoring that stupid incorrect error).

It can be automatically corrected, but it does result in some silly looking code:

var foo;
var bar;
foo = "Foo";
bar = "Bar";

When refactoring your code with the above, such as to move the bar variable down in to a separate function, more work is needed to shift things around than if the following were done instead:

var foo = "Foo";
var bar = "Bar";

I don’t want it corrected. I think the way I code it more accurately reflects how JavaScript works and that both of the alternatives are misleading.

bar gets declared before a value gets assigned to foo - my way reflects that whereas both of the others are misleading.

[quote=“felgall, post:4, topic:221408, full:true”]
I don’t want it corrected. I think the way I code it more accurately reflects how JavaScript works and that both of the alternatives are misleading.[/quote]

I felt that way too when it came to assembly language. It’s a tricky balance to maintain, representing what is actually happening versus ability to work with the code.

In the interest of learning more, what potential problems do you foresee occurring when variables are declared at the top of their scope when using this syntax?

var foo = "Foo";
var bar = "Bar";

As compared with when using this syntax?

var foo, bar;
foo = "Foo";
bar = "Bar";

As long as people realise that the declarations all happen before the first assignment there shouldn’t be any problems.

There is minimal code there preceding the apparent declaration of bar. The further the difference between the actual declaration of bar and its apparent definition, the more possibility of code in between malfunctioning because of code that assumes bar is not yet declared.

For less skilled people, isn’t that something that code linters will easily catch?
I foresee a problem with declaring the variables separately at the top.

The following code will be considered by a linter to be correct, because the variable is already declared:

var foo, bar;
foo = "Foo";
doSomething(bar);
bar = "Bar";

whereas, the following code will result in linters catching the error, because the linter can catch the intent of the undeclared variable being used, even though JavaScript still has it declared as being undefined.

var foo = "Foo";
doSomething(bar);
var bar = "Bar";

And yes, declaring a variable later on is another code smell that it easily found too.

That is perfectly valid code - bar does already exist at that point - only its value is undefined.

There is a very real difference between a field that is undeclared and one that is declared but has not yet had a value assigned. That’s why the only one var at the top concept was introduced in the first place.

There are some areas of JavaScript where it can make a significant difference to the processing whether a field is declared but has not yet had a value assigned to it or whether it has had a value assigned.so understanding the difference between the two is important.

Anyway,

var foo = "Foo";
var bar = "Bar";

does not take into account where the value to be assigned to bar involves calculations.

For example if the value of bar is dependent on an if statement.

if (x > 0) bar = "positiive";
else bar = 'Not Positive";

where does the var go in that code? (Let’s assume x is a parameter passed into the current function so that it can have any value without it affecting the declaration and assignment of foo).

That seems to be a strawman argument, for there are plenty of fully valid solutions to your man of straw. Let me thrash it for a while.

There are a number of options there.

You could use a ternary statement:

var bar = (x > 0) ? "positive" : "Not Positive";

You could use a function that performs the check (which puts off the problem):

var bar = getState(x);

or, you could declare one of the values by default, then change it later:

var bar = "Not Positive";
if (x > 0) {
    bar = "positive";
}

The choices are near-endless, depending on the intent that you wish to convey.

So to answer your question of “where does the var go in that code?” - the answer is, as always, right at the top.

The if statement was a simple example - for more complex alternatives only the - create another function that will only ever be run form this one spot - will work. That’s one extra function for every variable used by this function just in order that the variable has one first assignment to attach the var to.

Also no matter which way you write it doesn’t change the fact that bar is being declared before any values are assigned so my version more accurately reflects the order in which the code executes for the rare case where it actually makes a difference.

Consider the following:

function doSomething(x) {
 var myArray;
 myArray = [x];
 myArray.forEach(function(a) {console.log(a);}) ;
}
var foo = "Foo";
doSomething(bar);
var bar = "Bar";

given that the var statement for bar comes after the doSomething call a person not realising that bar gets declared before the foo assignment might expect that the forEach statement shouldn’t output anything as there are no declared entries in the array whereas in fact bar has been declared and so that method would output a value for it. With my version of the code it is more obvious that bar is declared at the time of running the function. Also even if the var declaring bar does come after the doSomething(bar) the error is that the declare isn’t above the use of bar in that call - the error isn’t that the call is being done before a value is assigned to bar - the function might expect to be called both before and after values are assigned.

So how would you modify:

var foo = "Foo";
doSomething(bar);
var bar = "Bar";

so that the var bar occurs prior to the doSomething() without changing the value that my doSomething() function outputs?

Currently the code relies on what is called a side-effect, where a declared variable is undefined until it’s actually declared.

I would declare bar as being undefined, then assign a value to it later. This helps to inform anyone reading the code clearly about my intention, so that possible thoughts about whether I intended it or not are less likely to occur.

var foo = "Foo";
var bar = undefined;
// do stuff with undefined bar
...
bar = "Bar";

That statement is just nonsense and is indicative of the mistake people keep making regarding where variables are declared in JavaScript - ALWAYS BEFORE THE FIRST STATEMENT EXECUTES. In your code bar is still being actually declared before the assignment to foo regardless of where in the code the var bar appears.

Perhaps you meant “a variable doesn’t exist at all until it is declared and a declared variable is considered to have a value of undefined until such time as an assignment statement assigns a different value to it.”

I think this demonstrates the problem you asked me about earlier. Having multiple var statements misleads people into incorrect thinking as with your incorrect statement regarding where bar is actually declared. If you (who know JavaScript really well) can make such incorrect statements regarding where the variables are actually declared then what chance do we have of teaching people where the declarations really happen unless we write the code to match?

[quote=“felgall, post:12, topic:221408, full:true”]

That statement is just nonsense and is indicative of the mistake people keep making regarding where variables are declared in JavaScript - ALWAYS BEFORE THE FIRST STATEMENT EXECUTES. In your code bar is still being actually declared before the assignment to foo regardless of where in the code the var bar appears.[/quote]

The bar variable is undefined before the first statement executes. I mean what I said - a declared variable is undefined until it’s actually declared.

I will be charitable and believe that you misunderstood me to say “is undeclared until it’s actually declared” which is definitely wrong.

The following code should help to clear this up:

var foo = "Foo";
log.innerHTML += "Foo and Bar before bar is declared.<br>";
log.innerHTML += "Foo " + foo + "<br>";
log.innerHTML += "Bar " + bar + "<br>";
var bar = "Bar";
log.innerHTML += "Foo and Bar after bar is declared.<br>";
log.innerHTML += "Foo " + foo + "<br>";
log.innerHTML += "Bar " + bar + "<br>";

Results in:

Foo and Bar before bar is declared.
Foo: Foo
Bar: undefined
Foo and Bar after bar is declared.
Foo: Foo
Bar: Bar

Because, a declared variable is undefined until it’s actually declared.

With the following code

var foo = 'Foo';
var bar = 'Bar';

both foo and bar are ACTUALLY declared before the value is assigned to foo.

Your statement is incorrect because before they are actually declared (as opposed to where the declaration appears in the code) they don’t exist.

The variables have a value of undefined between where they are actually declared (at the top of the code) and where a value is first assigned to replace it - regardless of whether this assignment appears before or after the apparent declaration in the code.

All variables declared in a function are ACTUALLY declared before any of the statements in that function are run - regardless of where the apparent declaration appears in the code.

The execution order for:

var foo = 'Foo';
var bar = 'Bar';

is:

  1. declare foo and bar
  2. assign a value to foo
  3. assign a value to bar

I think that we’re talking past each other.

We both agree that between the start of a block of code, and the place that “var bar” is written, that the variable still exists from the beginning of that block as an undefined variable.

The rest seems to be a misunderstanding of what “declared variable” means. For me, it means the place where the coder writes “var bar = …” with the understanding that the variable is undefined between the start of the block of code and that place where the you declare the defined variable.

If I am wrong I would love to be directed to suitable reference material to clear up the matter.

For what it’s worth, I’ve been declaring my variables at their point of first use for a long time, and I rely on linters to catch hoisting mistakes.

var x = 42;
function f() {
    console.log(x);
    var x;
}

JsLint will report “‘x’ is out of scope”, and JsHint will report “‘x’ was used before it was defined”.

I agree. The former – though technically valid – is almost certainly a mistake and won’t be caught by a linter.

1 Like

I agree.[quote=“Paul_Wilkins, post:5, topic:221408”]
In the interest of learning more, what potential problems do you foresee occurring when variables are declared at the top of their scope when using this syntax?
[/quote]

The problems I foresee occurring is a misunderstanding of what “declared variable” means. Not much of a prediction since it has always been the case where the order of the code doesn’t match the exact execution order.

Where in the code the actual declaration is shown the declaration is hoist to the top of the function. The scope of the variables is the entire function and not just from where the declaration appears in the code.

When using ‘use strict’ any variable not declared generates a syntax error before any of the code in the function is run as that’s the point at which the declarations are run.

[quote=“felgall, post:17, topic:221408, full:true”]
The problems I foresee occurring is a misunderstanding of what “declared variable” means.[/quote]

Please clarify what I have misunderstood about a declared variable?

As a reminder - I have never said that a variable exists only from where the “var bar” is written, I have said that a variable is undefined up until that point. And I have always said that variables should be declared at the top of their scope.

If I haven’t misunderstood anything, then we both seem to be in agreement as to how JavaScript interprets the code. :scream_cat:

The reference to ‘actually declared’ is misleading - variables are declared at the top of their scope regardless of where the declaration appears.

So ‘actually declared’ can be interpreted two different ways - as being the actual spot where the declarations are run (as I interpret it to mean) or as the spot in the code where the var reference just happens to be (as you interpret it to mean).

Since the declarations are done before anything else regardless of where they appear even the following code will work:

if (x > 0) bar = "positive";
else var bar = 'Not Positive";

Note that I am not suggesting that this is a good way to write the code, just pointing out that bar is declared before anything is assigned to it even if it were to be coded like this.

I think the important thing is that people learn that regardless of where the declaration appears in the code that it will actually be run before any of the actual statements in the code are run.

If a particular arrangement is going to be detected as an error by linters then the linter is assuming that the person doesn’t fully understand how declaring variables actually works.

[quote=“felgall, post:19, topic:221408, full:true”]
The reference to ‘actually declared’ is misleading - variables are declared at the top of their scope regardless of where the declaration appears.[/quote]

By that reasoning, it seems that MDN var is also misleading with it’s copious use of “variable declarations” and “declared variables” to refer to the line of code that “var bar” has been written.

I don’t agree with that line of reasoning.

Even the ECMAScript 2015 standards paper that nobody reads (section 13.3.2 on page 196) says 'declares variables" in terms of the “var bar” line of code.

Perhaps you need a different word? Initialize is one that the specs uses, that more clearly conveys the desired intent.