- -- operator
- -= operator
- ++ operator
- += operator
- Accessing and setting content
- Array length
- Arrays
- Between braces
- Booleans
- Braces
- Callback function
- Calling the function
- Class
- Closure
- Code block
- Conditions
- Console
- Constructor
- Creating a p element
- Data types
- Destructuring
- Else
- Else if
- Equals operator
- Error Handling
- ES6
- Event loop
- Events
- Extend
- Fetch API
- Filter
- For loop
- Function
- Function name
- Greater than
- Head element
- Hoisting
- If statement
- JSON
- Less than
- Local storage
- Map
- Methods
- Module
- Numbers
- Overriding methods
- Parameters
- Promises
- Reduce
- Regular expressions
- Removing an element
- Replace
- Scope
- Session storage
- Sort
- Splice
- String
- Substring
- Template literals
- Tile
- Type conversion
- While loop
JAVASCRIPT
JavaScript Closure: Syntax, Usage, and Examples
A JavaScript closure is a function that retains access to variables from its parent function, even after the parent function has finished executing. Closures let you maintain state, create function factories, and manage private variables, making them a powerful tool in JavaScript.
How to Use Closures in JavaScript
Closures occur when a function is declared inside another function and keeps a reference to its outer function’s variables.
function outerFunction(outerVariable) {
return function innerFunction(innerVariable) {
console.log(`Outer: ${outerVariable}, Inner: ${innerVariable}`);
};
}
const newFunction = outerFunction("Hello");
newFunction("World"); // Output: Outer: Hello, Inner: World
outerFunction
returnsinnerFunction
.innerFunction
remembersouterVariable
, even afterouterFunction
has executed.
Closures work because of lexical scoping. When JavaScript executes a function, it first looks for variables inside that function. If it doesn't find them, it looks at the parent scope, continuing up until it reaches the global scope.
When to Use Closures in JavaScript
Closures shine when you need:
- Data Privacy – Encapsulate variables so they are not accessible outside a function.
- Function Factories – Create functions dynamically with preset values.
- Callbacks and Event Listeners – Retain context for asynchronous operations.
- Memoization and Caching – Store values for better performance.
- Module Pattern – Simulate private variables in JavaScript.
Examples of Closures in JavaScript
Creating Private Variables
If you want to prevent direct access to a variable but still modify it through controlled functions, closures help create private variables.
function counter() {
let count = 0;
return {
increment: function () {
count++;
console.log(`Count: ${count}`);
},
decrement: function () {
count--;
console.log(`Count: ${count}`);
},
getCount: function () {
return count;
},
};
}
const myCounter = counter();
myCounter.increment(); // Count: 1
myCounter.increment(); // Count: 2
console.log(myCounter.getCount()); // 2
myCounter.decrement(); // Count: 1
In this example, count
is private because it exists inside the counter
function. You can only modify it through the increment
, decrement
, and getCount
methods.
Function Factories
Closures allow you to generate functions dynamically with specific behaviors.
javascript
CopyEdit
function multiplier(factor) {
return function (number) {
return number * factor;
};
}
const double = multiplier(2);
console.log(double(5)); // Output: 10
const triple = multiplier(3);
console.log(triple(5)); // Output: 15
Each time you call multiplier
, it creates a new function with its own factor
value.
Closures in Asynchronous Code
Closures help retain values in asynchronous operations, such as event handlers and timers.
function delayedGreeting(name) {
setTimeout(function () {
console.log(`Hello, ${name}!`);
}, 2000);
}
delayedGreeting("Alice"); // Output (after 2 sec): Hello, Alice!
Even after delayedGreeting
has finished executing, the setTimeout
function still has access to name
.
Looping with Closures
If you’ve used var
inside a loop, you may have encountered unexpected behavior:
for (var i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i); // Output: 3, 3, 3
}, 1000);
}
Since var
is function-scoped, all callbacks reference the same i
, which becomes 3
after the loop finishes.
To fix this, use let
, which is block-scoped:
for (let i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i); // Output: 0, 1, 2
}, 1000);
}
Another workaround is to use an IIFE (Immediately Invoked Function Expression) to create a new scope for each iteration:
for (var i = 0; i < 3; i++) {
(function (i) {
setTimeout(() => {
console.log(i); // Output: 0, 1, 2
}, 1000);
})(i);
}
Learn More About Closures in JavaScript
Closures and Memory Management
Closures can cause memory leaks if they retain large variables unnecessarily. The garbage collector cannot free memory if there are lingering references.
function createClosure() {
let largeArray = new Array(1000000).fill("data");
return function () {
console.log(largeArray.length);
};
}
let closureFunction = createClosure();
closureFunction();
// Remove reference to allow garbage collection
closureFunction = null;
Releasing references ensures JavaScript can reclaim memory.
Closures in JavaScript Scope
Closures work because of JavaScript’s lexical scope. Functions have access to variables from their parent scope, even if the parent function has finished executing.
function outer() {
let message = "I'm inside outer";
function inner() {
console.log(message);
}
return inner;
}
const closureExample = outer();
closureExample(); // Output: I'm inside outer
The inner
function maintains access to message
, even though outer
has completed execution.
Closures in Async Programming
Closures help maintain state in asynchronous code, including promises and event listeners.
function fetchUserData(userId) {
fetch(`https://jsonplaceholder.typicode.com/users/${userId}`)
.then(response => response.json())
.then(data => {
console.log(`User: ${data.name}`);
});
}
fetchUserData(1);
Even after fetchUserData
runs, the .then()
callback still accesses userId
and data
.
Avoiding Common Closure Pitfalls
- Holding large objects in closures: Avoid keeping large arrays or objects inside closures unless necessary.
- Unintended variable sharing: Each function call should create a new closure to prevent unintended behavior.
- Closures inside loops: Use
let
or an IIFE to ensure each iteration gets a fresh copy of the variable.
JavaScript Closure Use Cases
- Encapsulation – Hide internal variables from direct access.
- Function Factories – Generate functions with preset parameters.
- Asynchronous Operations – Preserve data across delays or API calls.
- Event Listeners – Retain context for event-driven behavior.
- Memoization – Cache results to improve performance.
Closures are a fundamental concept in JavaScript. They let you manage scope effectively, create flexible functions, and optimize memory usage. By mastering closures, you’ll write more powerful and efficient JavaScript code.
Sign up or download Mimo from the App Store or Google Play to enhance your programming skills and prepare for a career in tech.