W3docs

JavaScript Variable Scope

Understanding the nuances of variable scope in JavaScript is crucial for any aspiring developer. This guide aims not only to elucidate the concept of variable

Scope is the part of a program where a variable is visible and can be used. Understanding scope is what lets you predict which value a name refers to, avoid accidental clashes between variables, and reason about why a variable is or isn't available at a given point. This guide explains the kinds of scope JavaScript has, how nested functions reach into the scopes around them, how var differs from let/const, and how all of this leads naturally into closures.

The three kinds of scope

JavaScript decides variable visibility based on where the variable is declared in the source code — this is called lexical (or static) scope. There are three levels:

  • Global scope — declared outside any function or block. Visible everywhere.
  • Function scope — declared inside a function. Visible only within that function (this is how var works).
  • Block scope — declared with let or const inside a block { ... } (an if, a for, or even a bare {}). Visible only within that block.

Global scope

A variable declared at the top level of a script is global: every function and block can read and write it.

javascript— editable

Globals are convenient but risky: any part of the program can change them, and two unrelated pieces of code can pick the same name and overwrite each other. Keep the global namespace small.

Function scope

A variable declared inside a function exists only while that function runs and is invisible from the outside.

javascript— editable

The try...catch lets the example keep running so you can see the error message instead of the script simply halting.

Block scope

let and const are scoped to the nearest enclosing block, not the whole function. A variable declared inside an if or for block disappears once the block ends.

javascript— editable

How nested functions see outer variables

When you nest functions, the inner function can read variables from every scope that surrounds it — its own, the enclosing function's, and the global scope. This chain of accessible scopes is called the lexical environment (or scope chain).

When JavaScript looks up a name, it starts in the current scope and walks outward until it finds the variable. If it reaches the global scope without finding it, you get a ReferenceError.

javascript— editable

The lookup only goes outward, never inward — outer() cannot see innerVar. This is exactly the mechanism that makes closures work: an inner function keeps access to its outer variables even after the outer function has returned.

var vs let and const

The scoping rules differ depending on how you declare a variable. var is function-scoped and ignores blocks, while let and const are block-scoped. This is one of the most common sources of bugs in older code.

javascript— editable

The classic trap is a loop that creates callbacks. With var there is a single shared variable; with let each iteration gets its own binding:

javascript— editable

For a deeper look at the quirks of var — including hoisting and the lack of block scope — see the old "var".

Hoisting and the Temporal Dead Zone

Declarations are processed before code runs. A var declaration is hoisted and initialized to undefined, so reading it before the assignment gives undefined rather than an error. let and const are also hoisted, but they stay in a Temporal Dead Zone (TDZ) — unusable until the line that declares them executes.

javascript— editable

Best practices

  • Prefer const, then let, avoid var. Block scope is more predictable and prevents accidental leaks and the loop-callback trap shown above.
  • Keep variables in the narrowest scope that works. Declare inside the block or function that needs them rather than at the top level.
  • Minimize globals. Fewer globals means fewer naming clashes and fewer values any code can quietly mutate.
  • Declare before use. Even though hoisting exists, relying on it makes code harder to read.

Conclusion

Scope controls where each variable is visible: global, function, or block. Nested functions form a lexical environment that lets inner code reach outward through the scope chain — the foundation of closures. Choosing let/const over var gives you reliable block scoping and avoids hoisting surprises. Next, study how functions capture their surroundings in JavaScript Closures and how returned functions behave in function expressions.

Practice

Practice
What are the types of JavaScript variable scopes?
What are the types of JavaScript variable scopes?
Was this page helpful?