Hoisting with let & const vs var in JS and TDZ?

Prerana NawarPrerana Nawar
3 min read

Hello, peeps!

Today, let's embark on an exploration into the depths of JavaScript's hoisting and examine the complicated world of the Temporal Dead Zone (TDZ).

Get ready for some thought-provoking examples that will clarify these ideas.

Hoisting: A Deeper Dive

To truly grasp hoisting, let's examine a more complex scenario involving functions and block-level declarations.

console.log(foo); // undefined
console.log(bar); // ReferenceError: Cannot access 'bar' before initialization

var foo = 'I am hoisted!';
let bar = 'I am in the TDZ!';

function hoistingExample() {
    console.log(foo); // I am hoisted!
    console.log(bar); // ReferenceError: Cannot access 'bar' before initialization
    var foo = 'Function scope hoisting!';
    let bar = 'Function scope TDZ!';
}

hoistingExample();

In this example, var foo is hoisted to the top of the function scope, but its value is still undefined until the actual declaration. On the other hand, let bar is hoisted to the top of the block (function in this case), but accessing it before declaration results in a TDZ error.

The Temporal Dead Zone Chronicles

Let's delve even deeper into the Temporal Dead Zone with a nested example.

function nestedExample() {
    console.log(outer); // undefined
    console.log(inner); // ReferenceError: inner is not defined

    var outer = 'I am in the TDZ!';
    if (true) {
        let inner = 'I am hoisted, but still in the TDZ!';
        console.log(inner); // I am hoisted, but still in the TDZ!
        console.log(outer); // I am in the TDZ!
        outer = 'I escaped the TDZ!';
    }

    console.log(outer); // I escaped the TDZ!
    console.log(inner); // ReferenceError: 'inner' is not defined
}

nestedExample();

In this scenario,

  1. console.log(outer); // undefined: var outer is hoisted, but undefined until the declaration.

  2. console.log(inner); // ReferenceError: inner is not defined: let inner is in the TDZ, causing a ReferenceError.

  3. console.log(inner); // I am hoisted, but still in the TDZ!: Inside the if block, inner is accessible.

  4. console.log(outer); // I am in the TDZ!: var outer is accessible and logged within the block.

  5. console.log(outer); // I escaped the TDZ!: Updated value of outer logged outside the block.

  6. console.log(inner); // ReferenceError: 'inner' is not defined: Attempting to access inner outside the block results in a ReferenceError.

Temporal Dead Zone (TDZ) โ€“ the time between hoisting and variable initialization. Any line of code before the declaration and initialization of a let variable is considered the TDZ for that variable.

let a = 10;
var b = 15;

console.log(window.b); // 15
console.log(window.a); // undefined

In this example, until the line let a = 10, a is in the TDZ and cannot be accessed. This applies not only to the global context (window or this) but also to any other scope.

Stricter than Strict: const

Now, let's talk about const. It's the strictest of them all. Once a value is assigned to a const variable, it cannot be reassigned. This adds an extra layer of immutability to your code.

Best Practices

To navigate through these intricacies, here are some best practices:

  • Prefer const: Use const whenever possible. It enhances code readability and ensures immutability.

  • Fallback to let: If reassignment is necessary, use let. Avoid var as it may lead to unexpected behavior.

  • Declare and Initialize at the Top: To minimize the TDZ window and prevent errors, declare and initialize variables with let at the top of their scope.

These techniques will help you develop more reliable, cleaner JavaScript code.

Thank you! ๐Ÿš€

0
Subscribe to my newsletter

Read articles from Prerana Nawar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Prerana Nawar
Prerana Nawar