var vs let | let vs const
DEV Community

var vs let | let vs const

This post covers concepts related to the use of var, let and const keywords in ES6. We will compare based on the below various properties like scope, hoisting and accessibility, this, assignment and redeclaration, temporal dead zone and accessibility, and error handling.

Before jumping on to the applicable differences, let us first understand the meaning of "scope".

Scope

Scope of a variable is the region of your program in which it is defined/accessible, and is generally defined using a block using braces ({}).

NOTE: Scope is always associated with a declared identifier (such as a variable, a function, a class, or a parameter). It is not an independent entity; rather, it describes where that identifier is visible and can be accessed.

var is function-scoped & let is block-scoped

A variable declared using the var keyword belongs to the entire function, even if declared inside a block.

function test() {
  if (true) {
    var x = 10;
  }
  console.log(x);
}
test(); // logs 10

let belongs to the nearest block ({}).

function test() {
  if (true) {
    let x = 10;
  }
  console.log(x);
}
test(); // gives ReferenceError: x is not defined

Global var becomes a property of globalThis

In browsers, whether you do var x = 10; or globalThis.x = 10 both mean the same. But if one does:

let y = 20;
console.log(globalThis.y); // logs undefined

It does not create a property on the globalThis object. If x was declared with var, it exists. If it was declared with let, it doesn't.

Redeclaration

var allows redeclaration.

var a = 10;
var a = 20;
console.log(a); // logs 20

function example() {
  for (var i = 0; i < 5; i++) { }
  for (var i = 0; i < 10; i++) { }
}
// There is actually only one i variable.
// Each loop simply resets it.

let does not allow redeclaration.

let a = 10;
let a = 20; // gives SyntaxError

function example() {
  for (let i = 0; i < 5; i++) { }
  for (let i = 0; i < 10; i++) { }
}
// These are two different variables.
// Each loop gets its own _i_

Hoisting

Hoisting is probably the most confusing for beginners. Legacy JS used only var which is accessible even before declaration and assignment. Like below code:

console.log(x); // logs undefined
var x = 5;

Because it behaves similar to the below code:

var x;        // initialize
console.log(x);  // access
x = 5;        // assignment

The declaration moves, the assignment stays where it is. As a result, we do not get any reference error.

However, later on we have let and const keywords which assist with meaningful errors without returning undefined.

console.log(x);
let x = 5; // ReferenceError: Cannot access 'x' before initialization

Why? Because the variable is placed in the Temporal Dead Zone (TDZ) until the declaration executes. Here, the variable exists in the memory but is not accessible for the code.

These have a number of benefits such as:

  • It provides block scope, making variables behave more intuitively.
  • It prevents accidental redeclarations.
  • It avoids the confusing behavior of var hoisting by enforcing the Temporal Dead Zone, so using a variable before its declaration results in a clear error instead of silently yielding undefined.

Thanks for reading, if you came this far, please mention your thoughts / suggestions in the comments. Next article will cover optional chaining and short circuiting.

Comments

No comments yet. Start the discussion.