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.