Scopes
In JavaScript, scope refers to the area where a variable is accessible. It determines where in your code a particular variable can be used or modified. Think of scope as a boundary — variables defined inside a boundary can only be used within that boundary.
Understanding scope is important because it helps you avoid bugs caused by variables being accidentally changed or accessed from unexpected parts of your code.
// 'name' is accessible here because it is in the global scope
let name = "JavaScript";
function greet() {
// 'name' is accessible inside this function too
console.log("Hello, " + name);
}
greet(); // Output: Hello, JavaScript
Scoping is the process by which the JavaScript engine determines where variables and functions are accessible. When you write code, the engine uses scoping rules to figure out which variable you are referring to at any given point in the program.
JavaScript uses a set of rules to look up variables. It first checks the current scope. If the variable is not found there, it moves to the outer scope, and keeps going until it reaches the global scope. If the variable is still not found, a ReferenceError is thrown.
let language = "JavaScript";
function outer() {
let framework = "React";
function inner() {
// 'inner' can access 'framework' from outer() and 'language' from global scope
console.log(language); // Output: JavaScript
console.log(framework); // Output: React
}
inner();
}
outer();
JavaScript follows lexical scoping (also called static scoping). This means that the scope of a variable is determined by where it is written in the source code, not by where the function is called from.
In simple terms, a function can access variables from its own scope and from any outer (parent) scope where it was defined. This is what makes closures possible in JavaScript.
function outerFunction() {
let outerVar = "I am from outer function";
function innerFunction() {
// innerFunction can access outerVar because of lexical scoping
console.log(outerVar);
}
return innerFunction;
}
const myFunc = outerFunction();
myFunc(); // Output: I am from outer function
In the example above, innerFunction can
still access outerVar even after
outerFunction has finished running. This
is because lexical scoping keeps the reference to the
scope where the function was originally defined.
JavaScript has three main types of scope:
- Global Scope — Variables declared outside any function or block.
-
Functional Scope — Variables
declared inside a function using
var,let, orconst. -
Block Scope — Variables declared
inside a block (
{}) usingletorconst.
Let's look at each type in detail.
A variable has global scope when it is declared outside of any function or block. Global variables can be accessed from anywhere in the program — inside functions, inside blocks, or in the top-level code.
// Global variable
let color = "blue";
function printColor() {
console.log(color); // Output: blue
}
printColor();
console.log(color); // Output: blue
While global variables are useful for sharing data across your program, using too many can lead to naming conflicts and hard-to-find bugs. It's a good practice to keep the number of global variables to a minimum.
When a variable is declared inside a function, it has functional scope (also called function scope or local scope). This means the variable can only be accessed inside that function. It is not available outside of it.
function showMessage() {
let message = "Hello from inside the function!";
console.log(message); // Output: Hello from inside the function!
}
showMessage();
console.log(message); // ReferenceError: message is not defined
Variables declared with var,
let, or const inside a
function are all function-scoped. They cannot be
accessed from outside the function.
Functional scope also means nested functions can access variables from their parent function:
function outer() {
let x = 10;
function inner() {
let y = 5;
console.log(x + y); // Output: 15
}
inner();
console.log(y); // ReferenceError: y is not defined
}
outer();
Block scope was introduced in ES6
(ECMAScript 2015) with the let and
const keywords. A block is any code
inside curly braces {}, such as
if statements, for loops,
or while loops.
Variables declared with let or
const inside a block are only accessible
within that block. Variables declared with
var are not
block-scoped — they are function-scoped.
if (true) {
let a = 10;
const b = 20;
var c = 30;
}
console.log(c); // Output: 30 (var is NOT block-scoped)
console.log(a); // ReferenceError: a is not defined
console.log(b); // ReferenceError: b is not defined
Here is another example using a for
loop:
for (let i = 0; i < 3; i++) {
console.log(i); // Output: 0, 1, 2
}
console.log(i); // ReferenceError: i is not defined
// Compare with var
for (var j = 0; j < 3; j++) {
console.log(j); // Output: 0, 1, 2
}
console.log(j); // Output: 3 (var is NOT block-scoped)
Using let and const
instead of var is recommended because
block scoping makes your code more predictable and
easier to debug.
- Scope determines where a variable can be accessed in your code.
- Scoping is the process the engine uses to look up variables.
- Lexical scoping means scope is determined by where the code is written, not where it is called.
- Global scope — variables declared outside any function or block, accessible everywhere.
- Functional scope — variables declared inside a function, accessible only within that function.
-
Block scope — variables declared
with
letorconstinside a block ({}), accessible only within that block. -
varis function-scoped, whileletandconstare block-scoped.