What’s wrong with using ‘var’ in JavaScript?

Last updated: September 5, 2022.

Before the ES6 upgrade to JavaScript (2015) there was only one way to declare a new variable: using the var keyword.

The upgrade introduced two new keyword for declaring variables: let and const.

Since then, the use of var has generally become seen as something of a bad practice.

So, what exactly is wrong with using var?

Table of contents

Reasons not to use ‘var’

#1: ‘var‘ lacks block scope

Generally, you don’t want a variable created in a larger construct to be accessible outside it. When this occurs, it is known as ‘leakage’.

While this can sometimes be intentional, it can also occur accidently, leading to unwanted outcomes.

A feature of var is that is lacks block scope. This means that it is not contained within a loop or if...else statement.

Take the following example:

for (var i=0; i<=3; i++) {
  console.log(i); // 0 1 2 3
}
console.log(i); // 4

What you would probably want here is for i to exist only within the loop. But, because it has been declared with var, it 'leaks' out of its block scope and is available afterwards in the global scope.

Declare the variable with let and there is no leakage:

for (let i=0; i<=3; i++) {
  console.log(i); // 0 1 2 3
}
console.log(i); // Uncaught ReferenceError: i is not defined

#2: 'var' is hoisted

Try to do something with a non-existent variable and it, predictably, result in an error:

console.log(x); // Uncaught ReferenceError: x is not defined

But declare a variable afterwards using var and this changes:

console.log(x); // undefined
var x; // <-- Declaration is hoisted
x = 3; // <-- Value not hoisted

This is because the declaration of a variable with var is 'hoisted': at runtime, it is processed before anything else in its scope is executed. This is why you can make reference to it before it is created.

Note that the value is not hoisted. This is because variable initialization (assignment of a value to the variable) is not hoisted.

In other words, the code above is read as follows by the interpreter:

var x;
console.log(x);
x = 3;

This example is in the global scope but the same behavior also occurs inside of functions since var does have function scope.

With let and const, hoisting does not occur: you cannot access a variable before it is declared in your script:

console.log(x); // Uncaught ReferenceError: Cannot access 'x' before initialization

let x;

x = 3;

#3: A variable can be redeclared using 'var'

You usually don't want to create a variable under the same name as one you've already created because you then (perhaps unwantedly) lose the original value.

Instead, you'd want an error to be thrown so you can declare the variable under a different name.

But with var, no error is thrown. Instead, the original variable is silently overwritten:

var OG = "Al Capone";

console.log(OG); // Al Capone

var OG = "Baby Face";

console.log(OG); // Baby Face

Al Capone will not be happy.

Using let, you cannot use the same variable name twice:

let OG = "Al Capone";

console.log(OG); // Al Capone

let OG = "Baby Face"; // Uncaught SyntaxError: Identifier 'OG' has already been declared

console.log(OG);

Take that, Baby Face!

#4: 'var' creates properties on the window object

When using var in the global scope, you are creating new properties on the window object.

This is usually harmless, but can lead to unexpected outcomes.

For example, if you create a variable with the name of a method existing on the window object, it will silently overwrite it.

For example:

var fetch = "Bro";

console.log(window.fetch);

Uh oh, bro. You just overwrote the amazing fetch() function with the much less useful property value of "Bro".

Avoid these issues: use 'let' and 'const'

Though var is not 'broken' and its flexibility can make it more beginner-friendly, in practice it can lead to unexpected outcomes.

These potential pitfalls can be avoided by using let and const.

The differences between these two are:

  • Value must be assigned upon variable declaration?
    • const: yes ✔️
    • let: no ❌
  • Variable value can be reassigned later:
    • const: no ❌
    • let: yes ✔️

In other words, const is a stricter version of let, intended for initializing a variable with a value that shouldn't be overwritten.

But both avoid the problems associated with var outlined above.