Since the release of ECMAScript 2015, the de facto standard for declaring variables has been that we should use const
for those that don’t need to be reassigned, and let
for those that do. We’re told to forget about var
completely. But should we?
In this short post, I’ll explain how var
differs from let
and const
. Then I’ll share a simple method for deciding between var
and let
. Finally, I’ll link you to a thorough discussion that Kyle Simpson, a respected JavaScript veteran, has already written.
The var
keyword
The var
keyword has been around forever, and it’s not going anywhere. It declares variables either globally or locally to a function. This is in contrast with let
and const
, which declare block-scoped variables.
fn();
function fn() {
if (true) {
var a = "foo";
let b = "bar";
}
console.log(a); // logs "foo"
console.log(b); // throws a ReferenceError
}
When we invoke fn()
, the variable declarations inside the conditional block statement are evaluated, because the expression true
is obviously truthy. Because a
is declared using var
, it is scoped to the function. On the contrary, because b
is declared using let
, it is scoped to the block statement. We can log the value of a
after the block statement, but when we attempt to log the value of b
, we get a ReferenceError
.
Function scope versus block scope
The choice between var
and let
is a semantic one. If you need to use a variable throughout a function, use var
. If you only need it within a block, use let
. Both keywords are valid; it’s about choosing the right tool for the job.
When we invoke fn()
in this example, the value of the fiftyFifty
variable will either be 0
(a falsy value) or 1
(a truthy value). Depending on this value, we assign the variable foo
to the string "abc"
or "xyz"
. Because the var
keyword declares the variable in the scope of the function, we don’t need to declare it before the if...else
statement.
fn();
function fn() {
var fiftyFifty = Math.round(Math.random());
if (fiftyFifty) {
var foo = "abc";
} else {
var foo = "xyz";
}
console.log(foo);
}
Compare this with the let
keyword. We have to declare foo
before the if...else
statement, otherwise it would only be accessible within whichever block is executed. If you’re coming from another language, like Java, you may prefer this behaviour. But it’s worth considering whether the variable needs to be block-scoped here. I’d argue that it doesn’t, and that making it so introduces unnecessary complexity.
function fn() {
var fiftyFifty = Math.round(Math.random());
let foo;
if (fiftyFifty) {
foo = "abc";
} else {
foo = "xyz";
}
console.log(foo);
}
A thorough discussion
I was going to make a bigger case for the var
keyword, but Kyle Simpson has already done a fantastic job in Appendix A of You Don’t Know JS Yet: Scope & Closures. The relevant section is called The Case for var
. It’s an excellent read! If you want to debate it by email, I’d love to hear from you.