JavaScript > ES6 and Beyond > New Syntax and Features > let and const

Understanding `let` and `const` in JavaScript

This snippet explores the `let` and `const` keywords introduced in ES6, providing a comparison with `var` and demonstrating their usage and scope differences.

Basic Declaration and Assignment

The `let` keyword declares a block-scoped variable that can be reassigned. The `const` keyword declares a block-scoped constant that cannot be reassigned after its initial declaration. Attempting to reassign a `const` variable will result in a TypeError.

// Using let
let myVariable = 10;
console.log(myVariable); // Output: 10

myVariable = 20;
console.log(myVariable); // Output: 20

// Using const
const myConstant = 30;
console.log(myConstant); // Output: 30

// myConstant = 40; // This will throw an error: Assignment to constant variable.

Block Scope vs. Function Scope

`var` is function-scoped, meaning it's accessible throughout the function in which it's declared, even if it's declared inside a block (like an `if` statement). `let` and `const` are block-scoped, meaning they are only accessible within the block in which they are defined (e.g., within an `if` statement, a `for` loop, or a code block surrounded by curly braces `{}`).

// var (function-scoped)
function myFunction() {
  if (true) {
    var x = 10;
  }
  console.log(x); // Output: 10 - Accessible because var is function-scoped
}

myFunction();

// let (block-scoped)
function myOtherFunction() {
  if (true) {
    let y = 20;
    const z = 30;
  }
  // console.log(y); // This will throw an error: y is not defined
  // console.log(z); // This will throw an error: z is not defined
}

myOtherFunction();

Hoisting

Hoisting is JavaScript's behavior of moving declarations to the top of their scope before code execution. `var` variables are hoisted and initialized to `undefined`. `let` and `const` variables are also hoisted, but they are not initialized. This means that attempting to access them before their declaration results in a `ReferenceError` (the "temporal dead zone").

//Hoisting behavior with var, let and const
console.log(a); // Output: undefined - var is hoisted and initialized to undefined
// console.log(b); // This will throw an error: Cannot access 'b' before initialization - let is hoisted but not initialized
// console.log(c); // This will throw an error: Cannot access 'c' before initialization - const is hoisted but not initialized

var a = 10;
let b = 20;
const c = 30;

Real-Life Use Case: Loop Counters

When using `var` in loops with asynchronous operations (like `setTimeout`), the variable `i` is not scoped to each iteration. By the time the `setTimeout` callbacks execute, the loop has already completed, and `i`'s value is 5. `let` solves this issue by creating a new binding for `j` in each iteration of the loop, so each `setTimeout` callback closes over the correct value.

// Using var (problematic in loops)
for (var i = 0; i < 5; i++) {
  setTimeout(function() {
    console.log('var loop: ' + i);
  }, 100);
}
// Output: var loop: 5
//         var loop: 5
//         var loop: 5
//         var loop: 5
//         var loop: 5

// Using let (correct behavior)
for (let j = 0; j < 5; j++) {
  setTimeout(function() {
    console.log('let loop: ' + j);
  }, 100);
}
// Output: let loop: 0
//         let loop: 1
//         let loop: 2
//         let loop: 3
//         let loop: 4

Best Practices

  • Prefer `const` for variables that should not be reassigned. This makes your code more readable and helps prevent accidental modifications.
  • Use `let` for variables that need to be reassigned.
  • Avoid using `var` in modern JavaScript.
  • Declare variables at the top of their scope for clarity, even though hoisting occurs.

Interview Tip

Be prepared to explain the differences between `var`, `let`, and `const`, focusing on scope, hoisting, and mutability. Understand the implications of using `var` in loops and how `let` solves the common closure problem. Be ready to discuss the concept of the temporal dead zone.

When to Use Them

  • Use `const` for values that won't change, like API keys, configuration settings, or variables that are initialized once and never reassigned.
  • Use `let` for variables that need to be updated within a specific scope, such as loop counters or intermediate results.
  • Avoid `var` in modern JavaScript. If you're working with older codebases, understand its behavior and consider refactoring to use `let` and `const` where appropriate.

Memory footprint

The memory footprint of `let` and `const` is generally the same as `var`. The key difference is how the JavaScript engine manages the scope and mutability of these variables, not necessarily the amount of memory they consume directly. Using `const` can potentially allow the engine to perform some optimizations, knowing that the value won't change, but this is highly implementation-dependent.

Alternatives

There aren't really direct alternatives to `let` and `const` in modern JavaScript. `var` is the predecessor, but it has well-known drawbacks regarding scope. In some functional programming paradigms, you might favor immutability more heavily, reducing the need for `let` by designing functions to return new values instead of modifying existing ones.

Pros

  • `let` and `const` provide better scoping rules, reducing the risk of accidental variable overwrites and making code more predictable.
  • `const` enhances code readability by clearly indicating that a variable's value is not intended to change.
  • They improve code maintainability by making it easier to reason about variable usage within specific blocks of code.

Cons

  • The strict scoping can sometimes require more careful planning of variable declarations, especially when refactoring code that previously used `var`.
  • The immutability enforced by `const` can sometimes require more verbose code if you need to update complex data structures (though this is often mitigated by using immutable data structures).

FAQ

  • What happens if I try to reassign a `const` variable?

    You'll get a `TypeError: Assignment to constant variable.` error. `const` variables are meant to be immutable after their initial assignment.
  • Are `const` objects truly immutable?

    No. `const` means that the *reference* to the object cannot be changed. However, the properties of the object itself can still be modified. If you want true immutability, you can use `Object.freeze()`.
  • Can I declare a `const` variable without initializing it?

    No. `const` variables must be initialized when they are declared. Otherwise, you'll get a `SyntaxError: Missing initializer in const declaration`.