JavaScript Essentials

Understanding let, const, and Block Scoping

In modern JavaScript, the introduction of let and const keywords alongside the older var has significantly changed how we declare variables and manage their scope. Understanding these differences, particularly the concept of block scoping, is crucial for writing clean, predictable, and bug-free code.

What is Scope?

Scope refers to the accessibility (visibility) of variables. In JavaScript, variables can be declared in different scopes:

var: The Old Way (Function Scoped)

Before ES6 (ECMAScript 2015), var was the primary way to declare variables. A key characteristic of var is its function scoping, not block scoping. This means a variable declared with var inside a block (like an if or a for loop) is still accessible outside that block, but within its enclosing function or the global scope.


if (true) {
  var x = 10;
  console.log(x); // Output: 10
}
console.log(x); // Output: 10 (x is accessible outside the if block)

function myFunction() {
  var y = 20;
  console.log(y); // Output: 20
}
myFunction();
console.log(y); // Error: y is not defined (y is function-scoped)
                

Another behavior of var is hoisting. Variables declared with var are hoisted to the top of their scope (function or global) and initialized with undefined. This can sometimes lead to unexpected behavior.


console.log(z); // Output: undefined
var z = 30;
console.log(z); // Output: 30
                

let: Block Scoping and Reassignment

let was introduced in ES6 to provide block scoping. Variables declared with let are confined to the block in which they are declared.


if (true) {
  let a = 40;
  console.log(a); // Output: 40
}
// console.log(a); // Error: a is not defined (a is block-scoped)

for (let i = 0; i < 3; i++) {
  console.log(i); // Output: 0, 1, 2
}
// console.log(i); // Error: i is not defined (i is block-scoped to the loop)
                

Variables declared with let can be reassigned.


let count = 0;
count = 1; // Allowed
console.log(count); // Output: 1
                

Like var, let declarations are also hoisted, but they are not initialized. Accessing a let variable before its declaration results in a ReferenceError. This is often referred to as the "Temporal Dead Zone" (TDZ).


// console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 50;
console.log(b); // Output: 50
                

const: Block Scoping and No Reassignment

const also provides block scoping, similar to let. However, the key difference is that variables declared with const cannot be reassigned after their initial declaration.


const PI = 3.14159;
console.log(PI); // Output: 3.14159

// PI = 3.14; // TypeError: Assignment to constant variable. (Cannot reassign)

const person = { name: "Alice" };
person.name = "Bob"; // Allowed: Modifying properties of the object is fine
console.log(person.name); // Output: Bob

// person = { name: "Charlie" }; // TypeError: Assignment to constant variable. (Cannot reassign the object itself)
                

It's important to note that for objects and arrays declared with const, the variable itself is constant (cannot be reassigned to a new object/array), but the contents (properties or elements) can be modified.

const declarations also experience hoisting and the Temporal Dead Zone, just like let.


// console.log(MAX_SIZE); // ReferenceError: Cannot access 'MAX_SIZE' before initialization
const MAX_SIZE = 100;
console.log(MAX_SIZE); // Output: 100
                

It's a common convention to declare constants with all uppercase letters to make them easily identifiable.

Summary: When to Use What

Key Differences Table

Feature var let const
Scope Function or Global Block Block
Reassignment Yes Yes No
Redeclaration (in same scope) Yes No No
Hoisting Yes (initialized to undefined) Yes (TDZ, not initialized) Yes (TDZ, not initialized)
Block Scope Enforcement No Yes Yes

By adopting let and const and understanding their scoping rules, you can write more robust and maintainable JavaScript code. Embrace const for immutability and let for mutability within their intended scopes.