JavaScript Scope

Where variables live, which code can see them, and a gentle introduction to closures.

Lesson 19 of 56Intermediate13 min read

Scope answers one question: where can I use this variable? A variable created inside a function or inside a { } block only exists there. Code outside can't see it.

That might sound like a restriction, but it's what keeps large programs manageable. Without scope, every variable in every file would share one space, and two functions that both used a variable called total would overwrite each other. Understanding scope prevents a whole family of "is not defined" errors and leads to one of JavaScript's most useful features, closures.

Global, function and block scope

  • Global scope: variables declared outside every function and block. They're visible everywhere.
  • Function scope: variables declared inside a function. They're only visible inside that function.
  • Block scope: let and const declared inside any { }, such as an if or a loop, only exist inside those braces.

Inner code can see outer variables, but outer code can't see inner variables. Keep variables in the smallest scope that works. The fewer places a variable can be changed from, the easier your code is to reason about.

Shadowing

If an inner scope declares a variable with the same name as an outer one, the inner variable shadows, or hides, the outer one inside that scope. It's allowed, but it's confusing to read, so prefer different names.

Why modern code avoids var

var ignores block scope, so a var declared inside an if or a loop leaks out to the whole function. It's also hoisted with the value undefined, so using it too early gives undefined instead of a helpful error. let and const fix both problems, which is why modern code doesn't use var.

Hoisting in brief

Before running your code, JavaScript reads all the declarations in each scope. Function declarations are fully hoisted, so you can call them above the line where they're written. let and const are hoisted too, but they're locked until their line runs. That locked period is called the "temporal dead zone", and using a variable during it throws a clear ReferenceError.

Closures

A function remembers the variables that were around it when it was created, even after the outer function has finished running. That's called a closure:

JavaScript
function makeCounter() {
  let count = 0;
  return () => ++count;
}
const next = makeCounter();
next(); // 1
next(); // 2

count is private. Nothing outside can change it directly, but next can still read and update it. Closures are used for counters, settings that stay private, and event handlers that need to remember a value.

JavaScript Scope Syntax

Scope in brief

const appName = "Pixel";       // global
function demo() {
  const inside = "function";   // function scope
  if (true) {
    const block = "block";     // block scope
  }
}

JavaScript Scope Summary

  • Scope decides where a variable can be used.
  • Variables can have global, function or block scope.
  • Inner code can see outer variables, but not the other way round.
  • let and const respect block scope; var doesn't, so avoid it.
  • A closure is a function that remembers the variables around where it was created.

JavaScript Scope Examples

Each example runs in the page. Edit the code and press Run to see what changes.

Example 1

Global, function and block

const site = "Codevra";

function showScopes() {
  const lesson = "Scope";
  if (true) {
    const tip = "Use let and const";
    console.log(site, "|", lesson, "|", tip);
  }
  console.log(typeof tip);
}

showScopes();
console.log(typeof lesson);
ConsoleEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 1Global, so it's visible everywhere.
  2. Line 4Function scope, so it's only visible inside showScopes.
  3. Line 6Block scope, so it only exists inside the if braces.
  4. Line 7Inner code sees all three.
  5. Line 9Outside the block, tip doesn't exist ("undefined" from typeof).
  6. Line 13Outside the function, lesson doesn't exist either.
Example 2

var leaks, let doesn't

for (var i = 0; i < 3; i++) {}
console.log("var i after loop:", i);

for (let j = 0; j < 3; j++) {}
console.log("let j after loop:", typeof j);

if (true) {
  var leaky = "I escaped!";
  let safe = "I stayed inside";
}
console.log(leaky);
console.log(typeof safe);
ConsoleEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Lines 1 to 2var survives the loop, so i is 3 out here.
  2. Lines 4 to 5let stays inside the loop.
  3. Lines 7 to 10Inside the block: one var, one let.
  4. Line 11var ignores the block and leaks out.
  5. Line 12let respects the block, so safe doesn't exist here.
Example 3

A closure counter

function makeCounter(label) {
  let count = 0;
  return function () {
    count++;
    console.log(`${label}: ${count}`);
  };
}

const likes = makeCounter("❤️ Likes");
const shares = makeCounter("🔁 Shares");

likes();
likes();
shares();
likes();
ConsoleEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 2count is private to each call of makeCounter.
  2. Lines 3 to 6The returned function remembers count and label. That's a closure.
  3. Lines 9 to 10Two independent counters, each with its own count.
  4. Lines 12 to 15Likes reaches 3 while shares stays at 1.

Common JavaScript Scope Mistakes

Using a block variable outside its block

Don't
if (isMember) {
  const discount = 0.1;
}
console.log(discount); // ReferenceError
Do
let discount = 0;
if (isMember) {
  discount = 0.1;
}
console.log(discount);

Declare the variable in the scope where you need to use it.

Accidentally creating globals

Don't
function setup() {
  total = 0; // no let/const: becomes a global by accident
}
Do
function setup() {
  let total = 0;
}

Always declare variables with let or const.

JavaScript Scope in Real Projects

Scope keeps big apps sane

In a large app with hundreds of files, scope stops one part of the code from accidentally overwriting another's variables. Closures power private state, event handlers that remember data, and patterns like debounce that you'll meet in real projects.

JavaScript Scope Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Multiple choiceeasy

Where can a const declared inside an if block be used?

Predict the outputmedium

What does this print?

let x = "outer";
function test() {
  let x = "inner";
  console.log(x);
}
test();
console.log(x);
Predict the outputhard

What does this print?

function make() {
  let n = 0;
  return () => n += 10;
}
const add = make();
add();
console.log(add());
Fix the bugmedium

message is used outside the block it was declared in. Fix the code so it logs Status: Open without errors.

const hour = 10;

if (hour >= 9 && hour < 17) {
  const message = "Open";
} else {
  const message = "Closed";
}

console.log("Status:", message);
ConsoleEdit the code, then press Run or Ctrl+Enter
Checks
  • Logs "Status: Open"
  • No errors

JavaScript Scope Quiz

3 questions to check what you learned.

  1. Which keyword ignores block scope and should be avoided?

    • let
    • const
    • var
    • function
  2. What is a closure?

    • A function that closes the browser
    • A function that remembers variables from the scope where it was created
    • A finished loop
    • A way to end a program
  3. What happens if you use a let variable before its declaration line?

    • ReferenceError (temporal dead zone)
    • It's undefined
    • It's 0
    • It works normally

JavaScript Scope Challenge

Make a private wallet

Write createWallet(start) that:

  1. Keeps a private balance starting at start
  2. Returns an object with two functions: spend(amount) subtracts and returns the new balance, getBalance() returns the balance
  3. createWallet(50) → spend(20) returns 30, then getBalance() returns 30
function createWallet(start) {
  // your code
}

const wallet = createWallet(50);
console.log(wallet.spend(20));
console.log(wallet.getBalance());
ConsoleEdit the code, then press Run or Ctrl+Enter
Checks
  • spend returns the new balance
  • getBalance reflects spending
  • Wallets are independent
  • balance is private (not a property)