Closures are a powerful feature in JavaScript that allow functions to retain access to their lexical scope, even when the function is executed outside that scope. This can sound abstract, but with some simple examples, you'll see how closures can be both intuitive and incredibly useful in real-world applications.
What is a Closure?
A closure is created whenever a function is created - every function has an associated closure.
When a function is defined within another function, and the inner function retains access to the outer function’s variables. Essentially, a closure gives you access to an outer function’s scope from an inner function.
Here’s a simple definition:
- Closure: A combination of a function and its lexical environment within which that function was declared.
Basic Example
Let’s start with a basic example to illustrate the concept of closures:
function outerFunction() {
let outerVariable = 'I am from the outer function';
function innerFunction() {
console.log(outerVariable);
}
return innerFunction;
}
const myClosure = outerFunction();
myClosure(); // Outputs: I am from the outer function
In this example:
-
outerFunction
contains a variableouterVariable
and an inner functioninnerFunction
. -
innerFunction
accessesouterVariable
and logs it to the console. -
outerFunction
returnsinnerFunction
, and we store it inmyClosure
. - When
myClosure
is called, it still has access toouterVariable
even thoughouterFunction
has finished executing. This is a closure in action.
Real-World Example: Creating Private Variables
Closures are often used to create private variables in JavaScript. Here’s an example of how you can use closures to encapsulate data and provide a controlled interface to interact with it:
function createCounter() {
let count = 0;
return {
increment: function() {
count++;
console.log(count);
},
decrement: function() {
count--;
console.log(count);
},
getCount: function() {
return count;
}
};
}
const counter = createCounter();
counter.increment(); // Outputs: 1
counter.increment(); // Outputs: 2
counter.decrement(); // Outputs: 1
console.log(counter.getCount()); // Outputs: 1
In this example:
-
createCounter
function defines a variablecount
and returns an object with three methods:increment
,decrement
, andgetCount
. - The methods
increment
anddecrement
modifycount
, whilegetCount
returns its current value. - The
count
variable is private tocreateCounter
and cannot be accessed directly from outside. This encapsulation is made possible by closures.
Real-World Example: Delayed Execution
Closures are also useful for functions that need to remember the context in which they were created, such as setting up delayed execution with setTimeout
:
function greet(name) {
return function() {
console.log('Hello, ' + name);
};
}
const delayedGreeting = greet('Alice');
setTimeout(delayedGreeting, 2000); // Outputs: Hello, Alice after 2 seconds
In this example:
-
greet
function returns another function that logs a greeting message. -
delayedGreeting
stores the returned function with the capturedname
variable. -
setTimeout
executesdelayedGreeting
after 2 seconds, and it still has access toname
(Alice) due to the closure.
Conclusion
Closures are a fundamental concept in JavaScript that allow functions to access their lexical scope even after the outer function has finished executing. They enable powerful patterns such as data encapsulation, private variables, and delayed execution.
And Finally,
Please don’t hesitate to point out any mistakes in my writing and any errors in my logic.
I’m appreciative that you read my piece.
Top comments (2)
This is not correct. A closure is created whenever a function is created - every function has an associated closure. Nesting of functions is not required.
Misconceptions About Closures
Jon Randy 🎖️ ・ Sep 27 '23
Thanks for correcting me, Appreciated it.