The rule here is:
- Only one var statement per function
- That var statement must be at the top of the function
And to this day jslint, Crockford’s linting tool, errors out by default if you don’t follow this rule:
This code deceptively outputs “10”, because
var total has the effect of hoisting and declaring
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
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
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
And if you are using ES2015 or up, I’d even recommend using eslint to prevent the use of var entirely and forcing
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.