All seven differences between var, let and const in JavaScript

OpenJavaScript 0
Reading Time: 6 minutes 🕑

Last updated: February 15, 2022.

The differences between var, let and const in a table

In JavaScript, there are three ways to create a new variable: using the keyword var, let or const.

var is the oldest and original way to declare a new variable. But in 2015, let and const were introduced to the language to correct what are seen by many developers as problematic aspects of var.

Since their introduction, some developers have switched to exclusively using let and const to declare variables. But var is still commonly used in practice.

This article covers all seven differences between var, let and const so that you can make an informed choice about which to use and when.

#1: Top-level saving to global window object

When a new variable is declared with var in the global scope (i.e. not within a function or similar construct), it is saved as a new property on the global window object. This is not the case with let and const.

This can be demonstrated by creating three new variables in the global scope and logging the window object to the console afterwards:

var AAA = "I am the assigned value of var";
let AAB = "I am the assigned value of let";
const AAC = "I am the assigned value of const";

console.log(window);
Top-level saving to global window object: example output 1

The first aspect that is potentially problematic about this is that if a new variable with the same name is declared again, it will overwrite the property we have created without JavaScript throwing an error.

Second, built-in properties of the global window object can also be accidentally overwritten without error! For example, this is the output of the global window object if we create a variable named alert in the global scope using var:

var alert = "I am the assigned value of var";

console.log(window);
Top-level saving to global window object: example output 2

We just lost the built-in alert function! 😱

#2: Global v. module scope

When a new variable is declared using let and const at the top-level, it is scoped to that particular module. So if you are developing an app and declare variables with the same name in different modules, there is no conflict.

Because var is saved to the global window object, it is not module-scoped. So the potential issue of properties of the window object being silently overwritten – both for newly-created and built-in properties – arises across modules as well. The larger an app becomes, the greater the risk of an unwanted conflict.

#3: Redeclaring a variable

Declare two variables with the same name using var and no error will be thrown. Instead, the original variable will be (silently) overwritten:

var value = "I am the assigned value";
var value = "Step aside!";

console.log(value); 
// Step aside!

Though at first glance this makes var very flexible, it is possible to achieve the same result without redeclaring a variable. Just reassign a value instead:

var value = "I am the assigned value";
value = "Step aside!";

console.log(value); 
// Step aside!

For this reason, the flexibility of var to declare a variable with the same name twice is actually redundant from a functionality standpoint (while introducing the possibility of silent errors).

Try this with let or const and JavaScript will throw an immediate error before even executing your script. This is the case even if the redeclaration is nested within a function. For example:

console.log(2+2);

doubleDeclaration();

function doubleDeclaration() {
  let myLet = "I am the value";
  let myLet = "Replacement value";
}
Redeclaraing a variable: example output 1

Notice that console.log(2+2) is not printed, even though it occurs before the doubleDeclaration function is called.

This definitely prevents any redeclaration. But the extent of the error – bringing the entire script to a halt before it has even started to execute – could be overkill in some contexts.

#4: Hoisting and initialization

A variable declared with var is hoisted and initialized to the top of your script is defined in the global scope, and to the top of a function if declared within one. Variables declared with let and const are also hoisted, but not initialized.

To demonstrate this in practice, let's log an undeclared variable to the console. An error is thrown:

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

Now, if we intialize (i.e. declare and assign a value to) a let or const variable after console.log(myValue), JavaScript will logically throw an error stating that the value of the myValue variable cannot be accessed yet because it hasn't been initialized:

console.log(myValue);

let myValue = "I am the value";
// Uncaught ReferenceError: Cannot access 'myValue' before initialization

But try this with var and there is no error. Instead, console.log(myValue) returns a value of undefined:

console.log(myValue); // undefined

var myValue = "I am the value";

The difference occurs because JavaScript hoists any variable declared with var to the top of the script and initializes it with a default value undefined. If a variable is declared with var inside a function, it is hoisted and initialized before the function is executed.

Functions declared with the function keyword are also hoisted, allowing us to call them anywhere in our script (if they are defined in the global scope).

But for variables, no such advantage exists, so it is hard to argue against the behavior of let and const, which both throw hard error.

#5: Block scope

Both var, let and const have global scope if declared at the top-level. And all three have function scope if declared inside a function (i.e. they do not exist outside the function).

But they do differ in terms of block scope (i.e. inside if...else statements and loops),

Variables declared with var escape block scope. So for an if...else statement or loop in the global scope, var creates a new global variable:

if ((2+2)===4) {
    var message = "Correct!";
}
console.log(message); // "Correct!"

This behavior can be useful in some contexts, but runs the risk of overwriting variables created elsewhere in your script (and associated modules) and/or in-built properties on the global window object.

In contrast, let and const do not evade block scope and so are contained if declared within an if...else statement or loop:

if ((2+2)===4) {
    const message = "Correct!";
}

console.log(message);
// Throws hard error: "Uncaught ReferenceError: message is not defined"

Which behavior is desirable depends upon whether the declared variable needs to be accessed again outside of block scope.

But it is possible to have the best of both worlds – accessing the variable to which a value is assigned inside the block outside the block without the risk of overwriting properties of the window object – if let is used to declare a variable prior to a block statement:

let message;
if ((2+2)===4) {
    message = "Correct!";
}
console.log(message); // "Correct!"

#6: Can be declared without assigning a value

var and let share the flexibility that they can both be declared without the assignment of a value.

Try this with const and JavaScript will throw a hard error:

const x;
// Uncaught SyntaxError: Missing initializer in const declaration

Still, a const variable can be initialized as an empty array, object:

const array = [];
for (i=0; i<=5; i++) {
    array.push(i);
}
console.log(array); [0, 1, 2, 3, 4, 5]

#7: Value can be reassigned

Unlike var and let, the value of a variable declared with const cannot be reassigned:

const myData = ["User1","User2","User3"];

myData = ["User4", "User5", "User6"]; 

// Throws hard error: "Uncaught TypeError: Assignment to constant variable."

This protects the data inside a const variable from being overwritten with entirely new data.

But it can still be modified:

const myData = ["User1","User2","User3"];

myData.push("User4");

console.log(myData); ['User1', 'User2', 'User3', 'User4']

This makes const ideal for storing data that should not change or, at least, should only be modified from its original state.

Summary

When solving a programming problem, we want to select the right tool for the job while avoiding errors.

While the flexibility of var makes it appealing, it can also create hard-to-solve silent errors, with the probability of them increasing as a code base becomes larger. Probably, then, if you are working on constructing larger apps with multiple modules, let and const are the right choice.

On a smaller scale, however, code management is not such an issue. And the hard errors thrown by let and const can be off-putting, especially for beginners and developers who only want to write a few lines of JavaScript code. Thus, var is probably not going anywhere any time soon.