Closure Scope Chain
Closure scope chain refers to the hierarchy of nested functions and their respective scopes that closures have access to. The sum function creates nested closures, allowing access to variables like a, b, c, d, and e from different levels of scope within the chain.
function sum(a) {
return function(b) {
return function(c) {
return function(d) {
return function(e) {
return a + b + c + d + e;
};
};
};
};
}
const innermostClosure = sum(1)(2)(3)(4);
console.log(innermostClosure(5)); // Output: 15
Output of Code Snippet
The code snippet defines an immediately invoked function expression (IIFE) that declares a global variable count
and a local variable count
inside the printCount
function. The output will be 1 followed by 0 because of variable shadowing and the conditional check inside printCount
.
let count = 0;
(function() {
if (false) {
var count = 1;
}
console.log(count);
})();
// Output: 1 (due to variable shadowing) followed by 0
Function Similar to addSix() using Closures
The createBase
function returns a closure that adds a base number (6 in this case) to an inner number provided as an argument. The addSix
function created using createBase(6)
adds 6 to its argument when invoked.
function createBase(base) {
return function(num) {
return base + num;
};
}
const addSix = createBase(6);
console.log(addSix(10)); // Output: 16
Closures for Time Optimization
The find
function precomputes an array of squares and returns a closure that can access this precomputed data. This approach optimizes time by avoiding redundant computations, as demonstrated by the timed execution of closure(6)
and closure(50)
.
function find() {
const squares = [];
for (let i = 0; i <= 10000; i++) {
squares.push(i * i);
}
return function(x) {
return squares[x];
};
}
const closure = find();
console.time('Closure(6)');
console.log(closure(6)); // Output: 36
console.timeEnd('Closure(6)');
console.time('Closure(50)');
console.log(closure(50)); // Output: 2500
console.timeEnd('Closure(50)');
Private Counter Using Closure
The counter
function utilizes closure to create a private variable _counter
that can only be accessed and modified through the returned functions add
and retrieve
, ensuring data privacy and controlled access.
function counter() {
let _counter = 0;
return {
add: function() {
_counter++;
},
retrieve: function() {
return _counter;
}
};
}
const myCounter = counter();
myCounter.add();
myCounter.add();
console.log(myCounter.retrieve()); // Output: 2
Module Pattern Example
The Module Pattern uses an immediately invoked function expression (IIFE) to encapsulate private variables and functions, exposing only a public interface. In the given example, the module
object has a public method publicMethod
, while privateMethod
remains hidden within the module.
const module = (function() {
const privateMethod = function() {
console.log('This is a private method.');
};
return {
publicMethod: function() {
console.log('This is a public method.');
privateMethod();
}
};
})();
module.publicMethod(); // Output: "This is a public method." followed by "This is a private method."
Function Runs Only Once Using Closure
The Like
function returns a closure that tracks the number of times it has been called, ensuring its action (like subscribing) is performed only once. Subsequent calls to the closure display a message indicating that the action has already been performed.
function Like() {
let liked = false;
return function() {
if (!liked) {
console.log('Liked!');
liked = true;
} else {
console.log('Already liked!');
}
};
}
const likeAction = Like();
likeAction(); // Output: "Liked!"
likeAction(); // Output: "Already liked!"
Once Polyfill Using Closure
The once
function creates a closure that allows a given function to be executed only once. Upon the first call, the original function runs, and subsequent calls return the result of the initial execution, demonstrating how closure can control function execution.
function once(func) {
let executed = false;
let result;
return function(...args) {
if (!executed) {
result = func.apply(this, args);
executed = true;
}
return result;
};
}
const printMessageOnce = once(function(message) {
console.log(message);
});
printMessageOnce('Hello'); // Output: "Hello"
printMessageOnce('World'); // No output, function already executed
Memoize Polyfill Using Closure
The myMemoize
function is a memoization polyfill that caches function results based on arguments, using closure to store and retrieve cached values efficiently. This improves performance by avoiding redundant computations for repeated function calls with the same arguments.
function myMemoize(func) {
const cache = {};
return function(...args) {
const key = JSON.stringify(args);
if (!cache[key]) {
cache[key] = func.apply(this, args);
}
return cache[key];
};
}
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
const memoizedFibonacci = myMemoize(fibonacci);
console.log(memoizedFibonacci(10)); // Output: 55 (computed once and cached)
console.log(memoizedFibonacci(10)); // Output: 55 (retrieved from cache)