⬅ Previous Topic
JavaScript Hoisting - var, let, functionNext Topic ⮕
JavaScript Objects - Properties and Methods⬅ Previous Topic
JavaScript Hoisting - var, let, functionNext Topic ⮕
JavaScript Objects - Properties and MethodsIn JavaScript, a closure is formed when an inner function has access to variables from an outer function’s scope, even after the outer function has returned. This is possible because functions in JavaScript form lexical environments at the time of their definition.
Let’s start with a simple example to see how closures retain access to outer function variables.
function outer() {
let name = "JavaScript";
function inner() {
console.log("Hello from " + name);
}
return inner;
}
const greet = outer();
greet(); // calling inner function
Hello from JavaScript
When outer()
is called, it returns the inner
function. Even though outer()
has finished executing, the returned inner
function still "remembers" the variable name
from its lexical scope. This is closure in action.
Why does the inner function still have access to name
after outer()
returns?
Answer: Because the inner function forms a closure and "closes over" the variable name
. JavaScript's function scope retains access to variables from the context in which the function was defined.
Closures are often used to create data that cannot be directly accessed from the outside.
function createCounter() {
let count = 0;
return function() {
count++;
console.log("Count is", count);
}
}
const counter1 = createCounter();
counter1(); // Count is 1
counter1(); // Count is 2
Count is 1 Count is 2
The variable count
is not accessible from outside createCounter()
. But the returned function can access and modify it. This is a powerful technique for data privacy.
What happens if we create another counter?
const counter2 = createCounter();
counter2(); // Count is 1
Count is 1
Each call to createCounter()
returns a new closure with its own private count
.
Let’s look at how closures behave inside loops and how to avoid common pitfalls.
// Common mistake
for (var i = 1; i <= 3; i++) {
setTimeout(function() {
console.log("i:", i);
}, i * 1000);
}
i: 4 i: 4 i: 4
The setTimeout
callback forms a closure over the i
variable, which after the loop ends is 4. All three closures reference the same i
.
for (var i = 1; i <= 3; i++) {
(function(j) {
setTimeout(function() {
console.log("i:", j);
}, j * 1000);
})(i);
}
i: 1 i: 2 i: 3
for (let i = 1; i <= 3; i++) {
setTimeout(function() {
console.log("i:", i);
}, i * 1000);
}
Using let
ensures that each iteration of the loop has its own separate block scope for i
.
⬅ Previous Topic
JavaScript Hoisting - var, let, functionNext Topic ⮕
JavaScript Objects - Properties and MethodsYou can support this website with a contribution of your choice.
When making a contribution, mention your name, and programguru.org in the message. Your name shall be displayed in the sponsors list.