Scopes and Closure in Javascript

supraja
4 min readDec 30, 2023

--

image credit: link

In JavaScript, there are three main types of scopes:

1. Global Scope:

  • Variables declared outside any function have a global scope.
  • Accessible throughout the entire program.

2. Function Scope:

  • Variables declared inside a function have function scope.
  • Accessible only within the function where they are declared.

3. Block Scope (let and const):

  • Variables declared with let and const have block scope.
  • Accessible only within the block (e.g., if statement, for loop) where they are defined.
Variable scope

Let’s understand variable scope with examples:

In browsers, the global object is usually window. This means that you can access the variable using both the declared name and as a property of the global object, as shown below:

// Global Variable
globalVar = 42;
console.log(globalVar); // Accessing directly
console.log(window.globalVar); // Accessing as a property of the global object
// Variable with 'var' keyword
function exampleVar() {
// Function-scoped variable using var
if (true) {
var functionVar = 'I am a function-scoped variable (var)';
console.log(functionVar); // Output: 'I am a function-scoped variable (var)'
}
console.log(functionVar); // Output: 'I am a function-scoped variable (var)'
}
exampleVar();
// Accessing function-scoped variable outside the function
// console.log(functionVar); // Output: ReferenceError: functionVar is not defined
// Variable with 'let' keyword
function exampleLet() {
if (true) {
// Block-scoped variable using let
let blockScopedLet = 'I am a block-scoped variable (let)';
console.log(blockScopedLet); // Output: 'I am a block-scoped variable (let)'
}

// console.log(blockScopedLet); // Error: blockScopedLet is not defined
}
exampleLet();
// console.log(blockScopedLet); // Error: blockScopedLet is not defined

// Variable with 'const' keyword
function exampleConst() {
if (true) {
// Block-scoped constant using const
const blockScopedConst = 'I am a block-scoped constant (const)';
console.log(blockScopedConst); // Output: 'I am a block-scoped constant (const)'
// blockScopedConst = 'reassign value to const'; // Error: Assignment to constant variable.
}

// console.log(blockScopedConst); // Error: blockScopedConst is not defined
}
exampleConst();
// console.log(blockScopedConst); // Error: blockScopedConst is not defined

Prerequisites:

(1) Lexical Scope:

  • It is the way variables are scoped based on their location in the source code during the lexical analysis phase.
  • The scope of a variable is determined by where it is declared.
  • Lexical scope is fixed at the time of code writing and doesn’t change during the execution of the code.

(2) Lexical Environment:

  • A lexical environment is a data structure that holds variables and their values.
  • It is created for each function during the function’s creation phase.
  • It contains a reference to the outer (enclosing) lexical environment, forming a chain known as the “scope chain.”
function outerFunction() {
const outerVariable = 'I am outer';

function innerFunction() {
const innerVariable = 'I am inner';
console.log(outerVariable); // Access outerVariable from the outer scope
}

innerFunction();
}

outerFunction();

In this example, innerFunction has access to outerVariable because of lexical scope. The lexical environment of innerFunction includes a reference to the lexical environment of outerFunction, forming a chain that allows access to variables in the outer scope.

Closure:

A closure in JavaScript refers to the combination of a function and the lexical environment within which that function was declared. The lexical environment consists of the variables and their values that were in scope at the time the closure was created.

It is created when a function is defined inside another function (the outer function), and it has access to the variables of the outer function, even after the outer function has finished execution. In other words, a closure allows a function to “remember” and access its lexical scope, including the variables and parameters of its containing function.

Let’s understand with the example:

function outerFunction(x) {
// Inner function defined within the outer function
function innerFunction(y) {
return x + y;
}

return innerFunction; // Return the inner function (closure)
}

// Create a closure by calling outerFunction with argument 10
const closure = outerFunction(10);

// Use the closure to access variables from the outer function
const result = closure(5);
console.log(result); // Output: 15

In this example, innerFunction forms a closure because it references the variable x from its outer scope. When outerFunction(10) is called, it returns innerFunction as a closure. Later, invoking closure(5) still has access to the x value of 10 from the outer scope, resulting in the sum of x and y. This illustrates the concept of a closure in JavaScript.4

Lexical scope Vs Closure

lexical scope vs closure

Here’s a simple analogy:

Think of a closure like a backpack that a function carries with it. Inside the backpack are all the variables from its parent scope. Even when the function leaves its original environment (like when it finishes running), it still has the backpack with it, so it can always access those variables whenever it needs them.

So, in essence:

  • Lexical scope is about where a function can find and access variables.
  • Closure is about a function carrying around and using variables from its parent scope, even when it’s not there anymore.

--

--