JavaScript Scope

Where a Variable Is Visible

JavaScript Scope

Scope determines who can see a variable. JavaScript has block, function, module, and global scope.

5 min read Level 2/5 #scope#variables#block-scope
What you'll learn
  • Distinguish block, function, and module scope
  • Understand how nested scopes look up names
  • Know why variables in inner scopes can shadow outer ones

Scope is the region of code where a variable is accessible. JavaScript has four kinds:

ScopeWhere
BlockInside { }if, for, plain blocks
FunctionInside the function body
ModuleInside a module file
GlobalOutside everything

Block Scope

let and const are block-scoped — they only exist inside the nearest enclosing { }.

Block scope script.js
if (true) {
  const message = "inside";
  console.log(message);  // "inside"
}

// console.log(message); // ReferenceError — not defined here
▶ Preview: console

Function Scope

Every function creates its own scope. Variables declared inside aren’t visible outside.

Function scope script.js
function counter() {
  const start = 0;
  let n = start;
  n++;
  return n;
}

console.log(counter()); // 1
// console.log(start);  // ReferenceError
// console.log(n);      // ReferenceError
▶ Preview: console

Nested Scopes Look Outward

Inner scopes can read names from outer scopes. This is called lexical scope — what’s accessible depends on where the code is written, not who calls it.

Inner scope reads outer script.js
const outer = "I'm outside";

function inner() {
  console.log(outer);   // ✅ can see outer
  const x = "I'm inside";
  console.log(x);
}

inner();
// console.log(x);      // ❌ ReferenceError
▶ Preview: console

The chain goes from innermost outward: block → function → module → global. JavaScript stops at the first scope that has the name.

Shadowing

If an inner scope declares the same name, it shadows the outer one. The inner declaration takes precedence within its scope.

Shadowing script.js
const x = "outer";

function show() {
  const x = "inner";  // shadows the outer x
  console.log(x);     // "inner"
}

show();
console.log(x);       // "outer"
▶ Preview: console

Module Scope

Files imported with import (or marked type="module") have their own scope. Top-level let/const/function/class are visible only inside that file — unless you export them.

We’ll dig into modules in Section 6.

Global Scope

Variables declared at the very top of a non-module script become global. In the browser, that means window.X. In Node, globalThis.X.

var and Function Scope (Legacy)

var is function-scoped, not block-scoped. Declarations inside a block leak out:

var leaks script.js
function test() {
  if (true) {
    var leaky = "I leak";
    let trapped = "I don't";
  }
  console.log(leaky);     // "I leak"  — survives outside the if!
  // console.log(trapped); // ReferenceError
}

test();
▶ Preview: console

This is one of the main reasons let and const exist. Don’t write var in new code.

Up Next

A surprising consequence of function scope plus inner functions — closures.

JavaScript Closures →