Closure
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives a function access to its outer scope. In JavaScript, closures are created every time a function is created, at function creation time.
var num1 = 2;
function doSome() {
var num2 = 3;
return function () {
return num1 + num2;
};
}
var x = doSome();
console.dir(x);
// A closure is created with variable num2
var num1 = 2;
function doSome() {
var num2 = 3;
return function () {
return num1;
};
}
var x = doSome();
console.dir(x);
// Closure was not created since the num2 variable is not in used by the inner function
function init() {
var name = "Mozilla"; // name is a local variable created by init
function displayName() {
// displayName() is the inner function, that forms a closure
console.log(name); // use variable declared in the parent function
}
displayName();
}
init();
init() creates a local variable called name and a function called displayName(). The displayName() function is an inner function that is defined inside init() and is available only within the body of the init() function. Note that the displayName() function has no local variables of its own. However, since inner functions have access to the variables of outer scopes, displayName() can access the variable name declared in the parent function, init().
If you run this code in your console, you can see that the console.log() statement within the displayName() function successfully displays the value of the name variable, which is declared in its parent function. This is an example of lexical scoping, which describes how a parser resolves variable names when functions are nested. The word lexical refers to the fact that lexical scoping uses the location where a variable is declared within the source code to determine where that variable is available. Nested functions have access to variables declared in their outer scope.
function makeFunc() {
const name = "JavaScript";
function displayName() {
console.log(name);
}
return displayName;
}
const myFunc = makeFunc();
myFunc();
Running this code has exactly the same effect as the previous example of the init() function above. What’s different (and interesting) is that the displayName() inner function is returned from the outer function before being executed.
At first glance, it might seem unintuitive that this code still works. In some programming languages, the local variables within a function exist for just the duration of that function’s execution. Once makeFunc() finishes executing, you might expect that the name variable would no longer be accessible. However, because the code still works, this is obviously not the case in JavaScript.
The reason is that functions in JavaScript form closures. A closure is the combination of a function and the lexical environment within which that function was declared. This environment consists of any variables that were in-scope at the time the closure was created. In this case, myFunc is a reference to the instance of the function displayName that is created when makeFunc is run. The instance of displayName maintains a reference to its lexical environment, within which the variable name exists. For this reason, when myFunc is invoked, the variable name remains available for use, and “Mozilla” is passed to console.log.
Here’s a slightly more interesting example—a makeAdder function:
function makeAdder(x) {
return function (y) {
return x + y;
};
}
const add5 = makeAdder(5);
const add10 = makeAdder(10);
console.log(add5(2)); // 7
console.log(add10(2)); // 12
In this example, we have defined a function makeAdder(x), that takes a single argument x, and returns a new function. The function it returns takes a single argument y, and returns the sum of x and y.
In essence, makeAdder is a function factory. It creates functions that can add a specific value to their argument. In the above example, the function factory creates two new functions—one that adds five to its argument, and one that adds 10.
add5 and add10 both form closures. They share the same function body definition, but store different lexical environments. In add5’s lexical environment, x is 5, while in the lexical environment for add10, x is 10.
for (let i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i);
}, 1000 * i);
}
console.log("After for loop");
// After for loop
// 0
// 1
// 2
// After for loop printed first because of JS's asynchronous behaviour
for (var i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i);
}, 1000 * i);
}
console.log("After for loop");
// After for loop
// (3) 3
// Why 3 print's 3 times? Because `let` is block scoped means `i` exist only inside the loop and has no effects outside. since `let` doesn't leak outside the loop each iteration creates a new `i`. But `var` is function scoped and it exists outside the loop (lives in global), so changing `i` inside the loop modifies the same `i`