In JavaScript, scoping determines where variables and functions are accessible. Understanding how variables are scoped is essential to writing reliable, bug-free code. This guide covers all aspects of variable scoping in detail.
Scope is the region in your code where a variable is defined and can be referenced. Outside this region, the variable is invisible or inaccessible.
| Scope Type | Keyword(s) | Description |
|---|---|---|
| Global Scope | var, let, const | Declared outside all functions/blocks. Accessible anywhere in the file. |
| Function Scope | var | Declared inside a function with var. Accessible anywhere in that function. |
| Block Scope | let, const | Declared inside a block ({ ... }), such as if/for/while. Only accessible within that block. |
A variable declared outside any function or block becomes global. Global variables are attached to the window object in browsers.
var ocean = "Pacific";
function printOcean() {
console.log(ocean); // Accessible: prints "Pacific"
}
printOcean();
var)
var is function-scoped, meaning it's visible throughout the entire function in which it is declared, even before its declaration due to hoisting:
function demoVar() {
if (true) {
var fish = "tuna";
}
console.log(fish); // "tuna" (still accessible outside the if block)
}
demoVar();
let and const)
let and const are block-scoped. They are only available within the block { ... } where they are defined:
function demoLetConst() {
if (true) {
let crab = "blue";
const shell = "hard";
console.log(crab); // blue
}
// console.log(crab); // ReferenceError: crab is not defined
}
demoLetConst();
Hoisting is JavaScript's behavior of moving variable and function declarations to the top of their scope before executing code. Only var declarations are hoisted and initialized with undefined. let and const are hoisted but not initialized, leading to a "Temporal Dead Zone".
console.log(a); // undefined (hoisted)
var a = 5;
// console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 10;
let or const for block scoping.
A variable declared within a certain scope "shadows" (overrides) a variable with the same name in an outer scope.
let animal = "dolphin";
function zoo() {
let animal = "shark";
console.log(animal); // shark
}
zoo();
console.log(animal); // dolphin
JavaScript uses lexical scoping: a function’s scope is determined by where it’s defined, not where it’s called.
let fish = "goldfish";
function outer() {
let fish = "salmon";
function inner() {
console.log(fish);
}
inner();
}
outer(); // "salmon"
| Keyword | Scope | Hoisted | Re-declarable | Re-assignable |
|---|---|---|---|---|
| var | Function | Yes (initialized with undefined) | Yes | Yes |
| let | Block | Yes (not initialized) | No | Yes |
| const | Block | Yes (not initialized) | No | No |
const by default, let if the variable changes, and avoid var in modern code.