Use let instead of var in javascript

Table of contents

One of the first things new javascript developers are introduced to is the var keyword. What is often missing from this introduction is that it uses hoisting under the hood, ready to shoot you in the foot.

What is variable hoisting?

When using the var keyword in javascript, the variable definition (but not it's value!) is hoisted to the top of the current function scope. An example:

console.log(x) // returns "undefined", because the variable definition below is hoisted up but not it's initial value
var x = 10; // defines variable "x". the variable is available above this line, but will have a value of "undefined" until this line is reached
console.log(y) // throws ReferenceError, because the variable y is not declared anywhere

Notice how the variable x is usable before reaching the line it is defined in, but a variable that is not defined at all still causes a ReferenceError exception to tbe thrown. This behaviour is what hoisting means.

So why is var problematic?

Remember when we said that the variable definition is hoisted to the top of the function scope? That's really unintuitive when coming from other programming languages. Usually, a variable is scoped to it's parent block, commonly enclosed by curly brackets { ... }. In addition to that, redeclaring a variable using var is allowed and can be easily missed:

var x = 10
for (var i = 0; i < 3; i++){
   var x = i * 2;
   console.log(`Loop i=${i}, x=${x}`)
}
console.log(`Outer x: ${x}`)

Initially, one would assume that the second time var x is declared, it declares a local variable contained within the scope of the for loop. In most other languages this would be the case, and there is no syntax error in the code. But what really happens is that the second var does not declare a new variable - in fact, it changes the value of the x variable outside the for loop and quietly ignores the second var keyword entirely.

Enter let

Added in ES6 (Ecmascript2015), the let keyword comes to the rescue for developers getting stung by variable hoisting. By declaring a variable with let instead of var, it will behave more predictable as in other programming languages: A variable declared with let can't be used before the line it was declared in, scopes itself to the parent block and can't be redeclared withing the same block. An example:

let x = 10
for (let i = 0; i < 3; i++){
   let x = i * 2;
   console.log(`Loop i=${i}, x=${x}`)
}
console.log(`Outer x: ${x}`)

This time, the code works as expected, declaring 2 seperate variables named x, one outside and one inside the for loop. Using the same variable name in different scopes is allowed, but trying to redeclare an existing variable within the same scope will throw an error:

let x = 10 // initially declare x
let x = 11 // throws SyntaxError: Identifier 'x' has already been declared
x = 11 // assignment still works as expected

What about const?

The const keyword added alongside let behaves almost exactly the same, but doesn't allow assigning new values once declared. Additionally, you must provide a value when declaring it (as it can't be changed later and constants without values are really pointless):

const x = 10 // normal use
const x // throws SyntaxError: Missing initializer in const declaration
x = 11 // throws TypeError: Assignment to constant variable.
let y // unlike const, let can declare variables without initial values

This looks like constants you know from other programming languages, but it has a slight caveat: Variables declared const cannot be assigned a new value, but the one assigned to them can change. An example:

const x = {"name": "max"} // declare x as constant object
x.age = 19 // works, x is now { name: 'max', age: 19 }
delete x.name // also works, x is now { age: 19 }
x = {"name": "max"} // throws TypeError: Assignment to constant variable.

As you can see, we cannot directory give x a new value, but as long as we don't replace the reference to the object we initially gave to x entirely, we can change the contents of that object at will, deleting or changing keys that were initially defined or adding new ones. This works for both objects and arrays.



To sum it up, stop using var entirely. Every time you consider using var in your javascript code, let is the better choice. The decision between let and const is a less important one as their difference minor and the important behaviour is consistent across both. Real-world use cases for variable hoisting almost unanimously stem from bad code design that will be prone to bugs and hard to maintain in the future.

More articles

You may not need jQuery

But it's not a clear cut case

Avoiding pitfalls with the net/http package in go

Prevent nasty surprises when building http server apps in go

Concurrent worker pools in go

Distributing work among a fixed number of goroutines

Why boring software is a smart choice

Not everything is about excitement

Common pitfalls running docker in production

Avoiding the mistakes many make when embracing containerized deployments

Modern linux networking basics

Getting started with systemd-networkd, NetworkManager and the iproute2 suite