That’s why so many people who are using JavaScript remain unaware that the variable declarations are hoist to the top of their scope - which is what created the problem that a single var was supposed to fix in the first place.
I agree we should adopt MDN / ECMAScript terminology.
A variable is declared at the spot in the source code where the “var” statement appears, and a variable is created when a function is evaluated but before the function’s body is evaluated.
Getting back to the reason for the OP, declaring several variables with the one var statement tends to lead to this confusion. It all wouldn’t have happened if one var statement per declaration was used, as is the new recommendation from Douglas Crockford.
Or using the one var method I use - where the variables are declared at the same point as they are created - thus removing the need for the distinction as with my code the variables are created and declared at the same point.
Anyway we all agree that variables should all be declared at the top of the function whether with one var statement or one per variable. No one is proposing that we revert back to declaring variables when they are first referenced where other code not involving declarations precedes it.
Presumably the linter will still expect all of the var statements to occur prior to any other statements and will give an error if it finds a statement using var that appears after one that doesn’t use var. So that all of the declares are still as close to the point where the variables are created as they can be.
Reverting back to allowing the var to be anywhere would not detect
var foo = "Foo";
doSomething(bar);
var bar = "Bar";
as a likely error since bar is in fact declared.
Anyway, even better than using a linter to test declarations is to use ‘use strict’ which ensures that all variables are declared.
Actually, you’ll find that pretty much all linters will warn about the undeclared variable on the doSomething line. Even though it’s legal, it’s likely that the legal use of it is unintended.
Remember, even though the bar variable is declared after the function, the variable itself is created as undefined at the start of the block/function scope.
I agree up unto a point. Where I diverge from your opinion is at the point where linters cannot identify the intent of what you meant to code, which occurs when you manually declare all variables as undefined first before you then use them.
The following is a bad coding habit that allows unintended mistakes to slip through:
var foo, bar;
foo = "Foo";
doSomething(foo, bar);
bar = "Bar";
Not only do linters fail to spot the trouble with the bar variable - it also disguises a bad code smell.
A bad code smell is when a variable is accidentally declared as a global variable (which you’ll get more up-front warning about when in strict mode). The above coding practice is too close to that, to allow you to easily spot the problem.
Compare it with declaring each variable on their own separate line:
foo = "Foo";
doSomething(foo, bar);
var bar = "Bar";
Not only are you immediately aware that the bar variable is being declared possibly later than you intended, but it’s also crystal clear that something potentially wrong is happening with the foo variable.
The correct code would be:
var foo = "Foo";
var bar = "Bar";
doSomething(foo, bar);
This though is a direct attack against the way that you have been programming for years, which is going to be something of a controversy. Yes your way more correctly represents how the JavaScript interpreter behaves with variables, but programming in that way tends to create more potential problems.
It is the job of our programming practices to free us from having to consider such details so carefully (while still being aware of their impact), so that we can focus on the bigger picture at hand.
I know that you haven’t suffered much from the way that you program, because you are very skilled at what you do. What I seek is to protect other less-skilled up-and-coming programmers from being harmed by your current coding practice.
For the most part what I do is to teach others how to program in JavaScript and part of that is showing them where the variables are actually declared. I have been teaching the code the way I have it in order to match the declaration to where the variables are created in order that they can clearly see what variables the function actually uses - as well as that they all exist in scope right from the start of the function.
Not declaring all the variables at the start can also create problems if you need to change the code so that a variable now needs to be referenced earlier in the code than it was before the change.
Of course the following still counts as declaring all the variables at the start (even though the create and assign are not quite in the order the code suggests:
var foo = "Foo";
var bar = "Bar";
doSomething(foo, bar);
Now consider:
var foo = "Foo";
doSomething(foo);
// lots of statements
var bar = "Bar";
now all the variables are not declared at the start and if doSomething is modified to need to reference bar you have a problem - it may not even be clear that bar has been declared in this function. At least with my way you can tell that bar is declared and so doesn’t need to be declared again.
It would be so easy to not realise that bar is already declared and end up with
var foo = "Foo";
var bar = "Bar";
doSomething(foo, bar);
// lots of statements
var bar = "Bar";
[quote=“felgall, post:36, topic:221408, full:true”]
It would be so easy to not realise that bar is already declared[/quote]
There are at least two strong arguments against that opinion.
First, declaring variables anywhere by at the start of the block scope is a code smell that reeks to high heaven, and needs to be corrected straight away.
Second, any linter worth its salt will immediately pick up on the problem and inform you of of it too.
Regardless of code linters though, good programming practice makes it clear that there is an immediate problem.
Now for the opposing argument.
Where it is more difficult to tell if there’s a problem, is when the variable has already been created, and you then assign it without the var statement.
var foo, bar;
foo = "Foo";
doSomething(foo);
// lots of statements
bar = "Bar";
Not only is it difficult for a coder to determine that the bar variable is being assigned for the first time there, but linters also find it impossible to inform you about any possible issue too.
I do not find anywhere near enough good evidence to convince me that your coding practice is good or correct. It is more accurate I’ll grant you that, but it’s also more prone to error and unintended results.
When given two choices where one results in such potential errors and problems, and the other protects you from them, the correct choice is the one that results in less potential errors and problems.
Of course if your functions are written properly then trying to run code where variables are supposed to have had values assigned but haven’t will be immediately detected anyway without needing a linter to tell you.
I personally find having a list of all the variables a function uses as the first statement to be far more useful than having the linter tell me something that the code itself will tell me anyway the first time I try to run it.
Of course if you don’t write your functions to properly check their inputs then a linter will at least tell you whether a value has been assigned - even though the value may not be the correct type for the function to use.
[quote=“felgall, post:38, topic:221408, full:true”]I personally find having a list of all the variables a function uses as the first statement to be far more useful than having the linter tell me something that the code itself will tell me anyway the first time I try to run it.
[/quote]
That then is where we differ.
You say that declaring before assigning is more useful:
var foo, bar;
foo = "Foo";
bar = "Bar";
...
and I say that declaring the assignment is more useful:
var foo = "Foo";
var bar = "Bar";
...
As an expert it can be tempting to see declaring the assignment as a technique that beginners use, and seek to move away from such techniques.
Crockford tried to move away from it towards more sophisticated usage with the following sort of code:
var foo = "Foo",
bar = "Bar";
and it’s taken many years for him to realize that declaring the assignment may be the better way after all.
Let’s work this through. Two code examples, both exactly the same except for the var declarations.
// vars declared at top
var foo, bar;
foo = "Foo";
doSomething(foo);
// lots of statements
bar = "Bar";
// vars declared at first use
var foo = "Foo";
doSomething(foo);
// lots of statements
var bar = "Bar";
Then later the code is changed as your describe, “doSomething is modified to need to reference bar.”
// vars declared at top
var foo, bar;
foo = "Foo";
doSomething(foo, bar);
// lots of statements
bar = "Bar";
// vars declared at first use
var foo = "Foo";
doSomething(foo, bar);
// lots of statements
var bar = "Bar";
In this “vars at top” example, neither the interpreter nor a linter will flag an error. You’ll simply be passing undefined, a runtime error that you’ll have to debug.
Whereas in the “vars at first use” example, a linter will flag the problem immediately at design time.
With just two variables - or even a dozen, it makes little difference. - you can see all the variables being declared easily either way.
It is when you have several of those variables that are being declared that have rather long functions as the value being assigned so that the next var is dozens of lines of code below the current one that your way makes it almost impossible to tell.
Anyway the linter still can’t detect the following error:
var bar = "Bar";
addToCount(bar);
you still need to rely on code in addToCount to validate that the value passed is a numberr - and if addToCount validates that the value passed is a number it would reject undefined just as easily as it rejects ‘Bar’ as both are invalid.