Skip to main content
JavaScript Basics
CHAPTER 09 Beginner

JavaScript Scope and Hoisting

Updated: May 12, 2026
20 min read

# JavaScript Scope and Hoisting

Have you ever created a variable, tried to console.log() it on the next line, and JavaScript threw an angry red error saying ReferenceError: variable is not defined? You look at your code and say, "But it's right there!"

Welcome to the invisible rules of JavaScript: Scope and Hoisting.

1. Introduction

Scope determines the "visibility" or "accessibility" of variables, functions, and objects in some particular part of your code during runtime. Hoisting is a unique JavaScript mechanism where variable and function declarations are invisibly moved to the top of their scope before the code executes. Understanding these two concepts is what separates beginners from intermediate developers.

2. Learning Objectives

By the end of this chapter, you will be able to:

  • Identify Global Scope, Local (Function) Scope, and Block Scope.
  • Understand why var behaves differently from let and const.
  • Predict how JavaScript resolves variable names.
  • Understand the concept of "Hoisting" and how it affects your code.
  • Build a Scope Testing App to visualize where variables live and die.

3. The Three Types of Scope

Before ES6 (2015), JavaScript only had two types of scope: Global and Local. ES6 introduced let and const, bringing Block Scope to the language.

  1. 1. Global Scope: Variables declared outside any function or curly braces. They can be accessed from *anywhere* in your program.
  1. 2. Local (Function) Scope: Variables declared inside a function. They can *only* be accessed from inside that specific function.
  1. 3. Block Scope: Variables declared inside any curly braces {} (like if statements or for loops) using let or const. They cannot be accessed outside those braces.

4. Hoisting

Hoisting is JavaScript's default behavior of moving all declarations to the top of the current scope before executing the code.

Important: Only the *declaration* is hoisted, not the *initialization* (the value assignment).

---

5. Real-world Examples & Code Snippets

Example 1: Global Scope

javascript
12345678910
// Example JavaScript
let globalName = "Earth";

function printPlanet() {
    // The function can "see" the global variable
    console.log("We live on " + globalName);
}

printPlanet(); // Output: We live on Earth
console.log(globalName); // Output: Earth

Example 2: Local (Function) Scope

javascript
12345678910
// Example JavaScript
function createSecret() {
    let mySecret = "I love pizza";
    console.log("Inside function: " + mySecret); // This works
}

createSecret();

// Trying to access it outside the function
// console.log(mySecret); // ERROR: mySecret is not defined

Output Explanation: The variable mySecret is created when the function is called, and completely destroyed when the function finishes.

Example 3: Block Scope with let and const

javascript
12345678
// Example JavaScript
if (true) {
    let blockVariable = "I am trapped in this block!";
    const alsoTrapped = 100;
    console.log(blockVariable); // Works fine here
}

// console.log(blockVariable); // ERROR: blockVariable is not defined

Example 4: The Danger of var (No Block Scope)

This is why modern developers hate var. It ignores block scope!

javascript
1234567
// Example JavaScript
if (true) {
    var leakingVariable = "I escaped the block!";
}

// Even though it was inside the if-statement, var leaks out!
console.log(leakingVariable); // Output: I escaped the block!

Example 5: Nested Scopes (Lexical Scope)

Inner functions have access to the scope of their outer functions. This is called Lexical Scoping.

javascript
1234567891011121314
// Example JavaScript
function outerFunction() {
    let outerMoney = 100;
    
    function innerFunction() {
        let innerMoney = 50;
        console.log("Total: " + (outerMoney + innerMoney)); // Can see outerMoney
    }
    
    innerFunction();
    // console.log(innerMoney); // ERROR: Outer cannot see inner
}

outerFunction(); // Output: Total: 150

Example 6: Variable Shadowing

If you declare a variable with the same name inside a local scope, it "shadows" (hides) the global one.

javascript
12345678910
// Example JavaScript
let hero = "Batman";

function changeHero() {
    let hero = "Superman"; // Creates a NEW local variable
    console.log("Inside: " + hero); // Output: Superman
}

changeHero();
console.log("Outside: " + hero); // Output: Batman

Example 7: Function Hoisting

You can actually call a function *before* you write it in the code! JavaScript invisibly pulls the function declaration to the top.

javascript
123456
// Example JavaScript
fly(); // We call it up here!

function fly() { // We define it down here
    console.log("I am flying!");
}

Output Explanation: Works perfectly. Output: "I am flying!".

Example 8: Variable Hoisting with var

var variables are hoisted, but their values are not.

javascript
1234567891011
// Example JavaScript
console.log(myAge); // Output: undefined (no error!)
var myAge = 25;
console.log(myAge); // Output: 25

/* How JavaScript actually sees it behind the scenes:
var myAge;
console.log(myAge);
myAge = 25;
console.log(myAge);
*/

Example 9: Variable Hoisting with let and const

let and const are hoisted, but they are placed in a "Temporal Dead Zone" (TDZ). You cannot access them before initialization.

javascript
123
// Example JavaScript
// console.log(myScore); // ERROR: Cannot access 'myScore' before initialization
let myScore = 100;

Example 10: Best Practice for Declarations

Because of hoisting rules, it is a strict best practice to always declare your variables at the very top of their respective scopes.

javascript
12345678910111213
// Example JavaScript
function calculate() {
    // 1. Declare all variables at the top
    let a, b, total;
    
    // 2. Assign values
    a = 10;
    b = 20;
    
    // 3. Perform logic
    total = a + b;
    return total;
}

---

6. Common Mistakes for Beginners

  1. 1. Accidentally creating Global Variables: If you assign a value to a variable that hasn't been declared with let, const, or var, JavaScript will automatically make it a global variable, which can break your entire app.
javascript
1234567891011121314151617
   function badCode() {
       rogueVar = "I am global now!"; // Forgot 'let'
   }
   ```
2. **Confusing `var` and `let` inside `for` loops:** Using `var` inside a `for` loop causes the loop variable to leak out into the rest of your code. Always use `let i = 0;`.

## 7. Best Practices

- **Avoid Global Variables:** Only put variables in the global scope if absolutely necessary. Global variables can be overwritten by other scripts (like third-party plugins), causing nightmare bugs.
- **Always use `let` and `const`:** They enforce block scoping, which prevents bugs and makes your code predictable.
- **Declare at the top:** Always declare your variables at the top of your function or script to make hoisting obvious to humans reading the code.

## 8. Mini Project: Scope Testing App

Let's build a small UI that proves `var` leaks and `let` is secure.

**HTML:**

html <!-- Example HTML --> <!DOCTYPE html> <html> <head> <style> /* Example CSS */ body { font-family: Arial; padding: 20px; } .box { border: 2px solid #333; padding: 15px; margin-bottom: 10px; width: 300px; background: #f4f4f4;} button { padding: 10px; background: #333; color: white; cursor: pointer; border: none; } </style> </head> <body>

<div class="box"> <h3>Scope Tester</h3> <button onclick="runTest()">Run Block Test</button> <p id="varOutput"></p> <p id="letOutput"></p> </div>

<script src="scope.js"></script> </body> </html>

1
**scope.js:**

javascript // Example JavaScript function runTest() { // A block scope (like an if statement) if (true) { var leakyVar = "I am a VAR. I escaped the block!"; let secureLet = "I am a LET. I am trapped!"; }

// Try to access them outside the block // 1. VAR will succeed document.getElementById("varOutput").innerHTML = "Var Result: " + leakyVar; // 2. LET will fail (we have to use a try/catch to prevent the app from crashing, which we will learn later!) try { document.getElementById("letOutput").innerHTML = "Let Result: " + secureLet; } catch(err) { document.getElementById("letOutput").innerHTML = "Let Result: ERROR! " + err.message; document.getElementById("letOutput").style.color = "red"; } } `` How it works: When you click the button, it creates a var and a let inside an if block. It then tries to print them below the block. The var successfully prints. The let crashes and throws an error because it is safely destroyed at the end of the block.

9. Exercises

  1. 1. Create a global variable const prefix = "Hello ". Create a function that takes a name parameter, and console logs the prefix + the name.
  1. 2. Write a function with a let variable inside it. Call the function. Then, on the next line outside the function, try to console.log() the variable to see the ReferenceError.
  1. 3. Try to call a function on line 1, and define the function on line 5 to test Hoisting for yourself.

10. MCQs (Multiple Choice Questions)

Q1: Which variable declaration type is completely ignored by Block Scope {}? A) let B) const C) var D) static *Answer: C*

Q2: Variables declared inside a function are in the... A) Global Scope B) Local Scope C) Universal Scope D) Hoisted Scope *Answer: B*

Q3: What is Hoisting? A) Moving functions to another file. B) JavaScript's default behavior of moving declarations to the top. C) Elevating user permissions. D) Converting variables from strings to numbers. *Answer: B*

11. Interview Questions

Q: Explain the Temporal Dead Zone (TDZ). *A: The Temporal Dead Zone is the period between entering a scope and the actual declaration of a let or const variable. If you try to access the variable during this period (before it's initialized), JavaScript will throw a ReferenceError. This is different from var, which would just return undefined.*

Q: What is Lexical Scoping? *A: Lexical Scoping means that a function's scope is determined by its physical placement in the source code. Inner functions have access to variables declared in their outer functions' scope.*

12. FAQs

Q: If var is so bad, why does it still exist? *A: Backwards compatibility. If the creators of JavaScript removed var today, millions of websites built before 2015 would break instantly.*

13. Summary

  • Global Scope: Variables available everywhere. Avoid using them.
  • Local Scope: Variables trapped inside a function.
  • Block Scope: Variables trapped inside {}. Supported by let and const.
  • Hoisting: Declarations are pulled to the top. Functions can be called before they are written. var is hoisted as undefined. let/const` are hoisted into the Temporal Dead Zone.

14. Next Chapter Recommendation

Variables so far have only held one thing at a time (one string, one number). What if we want to store 100 students in a single variable? In the next chapter, JavaScript Arrays, we will learn how to group multiple pieces of data into powerful lists.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·