There’s no need to declare all javascript vars once at the top of a function, and there hasn’t been for a while.
Back in the bad old days of javascript, people suddenly started writing all of their code like this:
The rule here is:
- Only one var statement per function
- That var statement must be at the top of the function
This style gained a lot of popularity after Douglas Crockford’s JavaScript: The Good Parts:
JavaScript has C syntax, but its blocks don’t have scope. So, the convention that variables should be declared at their first use is really bad advice in JavaScript. JavaScript has function scope, but not block scope, so I declare all of my variables at the beginning of each function. JavaScript allows variables to be declared after they are used. That feels like a mistake to me, and I don’t want to write programs that look like mistakes.
And to this day jslint, Crockford’s linting tool, errors out by default if you don’t follow this rule:
But, why?
The reason is, as Crockford mentions: JavaScript allows variables to be declared after they are used. Dubbed “variable hoisting”, this has the potential to create subtle and dangerous bugs:
This code deceptively outputs “10”, because var total
has the effect of hoisting and declaring total
as undefined
at the top of the function, causing it to fail the truthiness check on line 8.
But is Crockford’s rule really necessary any more? The answer is no, not really.
Solution 1: Use let
Using ES2015/ES6, either in node or through babel, we can just write our code to use let
instead of var
, which gives our variables block scope, and does not hoist them.
This entirely sidesteps the problem, and means there’s no incentive any more to define multiple variables per let
statement, or to group all of their variable definitions at the top of a function — although for some reason you still see people doing this, even with let
.
But what about my existing javascript, that I haven’t converted to ES2015 yet?
Solution 2: Use eslint
Eslint catches variable hoisting kinds of bugs a mile off (with its default configuration), by throwing an error if:
- You redeclare a variable which has already been declared
- You try to use a variable before it has been declared
With these two simple rules, I’d challenge anyone to come up with a bug caused by variable hoisting, even if you continue to use var
.
And if you are using ES2015 or up, I’d even recommend using eslint to prevent the use of var entirely and forcing let
.
Solution 3: Keep using jslint (if you must)
Even jslint will complain if you use a variable out of scope, or redeclare a variable from the outer scope:
Given this, it’s a mystery to me why jslint still enforces the single-var rule by default. At the very least, there’s a multivar
option you can use to disable that rule.
—
In conclusion: please, please stop writing code with a bunch of variables declared in a single statement at the top of your function. It’s harder to maintain, reads less clearly, and in my mind has more potential to create bugs than preventing the problem it’s trying to solve. Like, for example, the risk of accidentally creating global variables if you forget to add some new variable to your single var statement, if you aren’t already using a linter.
Obviously, always use a linter (be safe, kids), because linters, even Crockford’s, invalidate the need to do single vars and catch variable hoisting before it happens. But if you don’t, or can’t, instead of following the single-var convention, follow these rules instead and you’ll have a much better time:
- Never redeclare a var from a parent scope, or use the same name twice
- Never reference a local variable before it is declared
Now you can learn to spot variable hoisting issues before they happen, rather than just blindly following an obscure single-var convention.
Thanks!