JavaScript variable declaration with var, let, and const

Published December 28, 2020

With the arrival of ES6 came the addition of let and const. These are useful for variable declaration. In this post, we'll see why they are different from var.

Variable declaration with var

Before ES6 arrived, var declarations were the way to go in JavaScript. Variables declared with var can have problems. This is why ES6 introduced new ways to declare variables. It will help to know more about var, we'll get a better understand of why let and const were created to replace var.

Var declarations

Variables declared with var can be re-declared and updated without an error. This can make var messy to work with.

With var, we can redeclare a variable by repeating the var keyword right before it. No error will be thrown.

var car = "Toyota";
var car = "Ford";
console.log(car); // Ford

We can also update the variable that we declared with var.

var car = "Toyota";
car = "Ford";
console.log(car); // Ford

Variable re-declaration with var can be problematic. If we deliberately want to redefine a variable defined with var, this is not a problem. However, if we do not realize that a variable has already been defined with var, and we redefine it, we can get unexpected results when our code runs. Here is an example of this problematic scenario.

var car = "Impreza WRX";
var horsepower = 350;

if (horsepower >= 350) {
  var car = "Corvette"; 
}

console.log(car) // Corvette

When we get to the if statement scope, we can forget that car was already previously defined with var. We can end up using the same variable name car with var in this scope. It will not throw an error, but instead quietly redefine our original car variable. While we may be expecting to see Impreza WRX as the output of the console.log() statement, we will actually get Corvette due to the accidental var re-declaration.

When a var variable is declared outside of a function, its scope is global. The outer car and horsepower variables are globally-scoped since they exist outside of a function.

Var Hoisting

JavaScript does something called hoisting. Hoisting is the behavior of moving variable and function declarations to the top of their current scope before execution. The current scope can be the top of a script or the top of a function. Declarations are hoisted to the top. var variables are hoisted to the top of their scope and are then initialized with an undefined value.

console.log (car); // undefined
var car = "Porsche";

Hoisting actually causes these lines to be interpreted as:

var car;
console.log(car); // undefined
car = "Porsche";

Variables that are defined with let and const solve the hoisting problem that exists with var. let and const variables are hoisted to the top of a code block, but they are not initialized. The code block knows about these variables but cannot use them until they are declared.

car = "Acura"; // variable usage
let car; // variable declaration

In the example above, using a let variable above before it has been declared results in the following console error: Uncaught ReferenceError: Cannot access 'car' before initialization.

car = "Nissan"; // variable usage
const car; // variable declaration

In the example above, using a const variable above before it has been declared results in a syntax error in the console that says error: unknown: Unexpected token.

Variable declaration with let

let is meant for variables that we want to reassign a value to. We let that variable be reassignable. There are some instances where this is helpful. Let's look at a simple case.

let total = 0;

[{ total: 1}, { total: 2}].forEach(item => {
  total += item.total; // reassign a new value to 'total'
});

console.log(total); // 3

let variables can be re-declared but they cannot be re-declared, which helps us to avoid the re-declaration issue that we encountered with var.

let car = "Maserati";
car = "Lotus"; // this is fine
    
let car = "Mazda";
let car = "Hyundai"; // error: unknown: Identifier 'car' has already been declared

Since let is block-scoped, you can define the same variable name in different scopes and not encounter an error for doing so.

let car = "Opel";
if (car) {
  let car = "Mitsubishi";
  console.log(car); // Mitsubishi
}
console.log(car); // Opel

There is no issue with this because both instances of car are seen as different variables because they have different scopes.

Variable declaration with const

const is meant for variables that will maintain a constant value. The value of a variable declared with const will not be allowed to change within its scope.

Every const variable declaration needs to be initialized at the time it is declared.

const car; // error: unknown: Unexpected token
const car = "Car"; // this is fine

Variables declared with const cannot be updated or re-declared.

const car = "Buick";
car = "BMW"; // error: Uncaught TypeError: Assignment to constant variable.

const car = "Mercedes";
const car = "Renault"; // error: unknown: Identifier 'car' has already been declared

Objects that are declared with const cannot be updated, but their properties can be updated.

const car = {
  brand: "Honda",
  model: "Civic",
  year: 2020
};

car = {
  horsepower: 200,
} // error: Uncaught TypeError: Assignment to constant variable.

car.horsepower = 300; // this is fine

We can add or update a property within a const object, such as horsepower, but we cannot update the car object itself.

Conclusion

var

  • var variables can be updated and re-declared
  • var variables are automatically initialized with undefined.
  • var variables can be declared without being initialized.
  • Don't use var.

let

  • let variables can be updated but not re-declared
  • let variables are not automatically initialized.
  • let variables can be declared without being initialized.
  • Use letif you want the variable to be reassignable.

const

  • const variables cannot be updated or re-declared.
  • const variables are not automatically initialized.
  • const variables need to be initialized when declared.
  • Use const whenever possible. It's added protection in your code since it guarantees that a value cannot be reassigned to it.