Practical Closure

A lifelong learner. Love to travel. Listen to music.
Search for a command to run...

A lifelong learner. Love to travel. Listen to music.
No comments yet. Be the first to comment.
Best Practices for Path Structure, Versioning, and Error Handling

Understanding the Performance Implications of async and defer Attributes

Overview static: Default position. It does not allow setting properties like top, bottom, left, right, z-index relative: Acts the same as static. but allows positioning it relatively by putting properties like top, bottom, left, right, z-index absolu...

Overview When an element in the browser has a conflict of styles, the browser uses a set of rules to determine which style should be rendered. This set of rules is defined as CSS Selector Specificity. For instance, for an element, if we have the foll...

Master block, inline, flex, and grid to build better web layouts

In some cases, closure can be tricky to predict. Gathered some of these concepts with code implementations to make the closure easy and interesting.
A function with a reference from the outer environment creates a closure.
function outer () {
var a = 'hello';
function inner() {
console.log(a);
}
return inner;
}
outer()(); // prints "hello"
It is not necessary to define variables above the function definition.
function outer() {
function inner() {
console.log(a);
}
var a = 'hello'; // define variable after function definition
return inner;
}
outer()(); // prints 'hello'
Instead of using var, we can use let or const instead.
function outer() {
function inner() {
console.log(a);
}
const a = 'hello';
return inner;
}
outer()(); // prints 'hello'
We can pass a parameter to the parent method and create a closure.
function outer(b) {
function inner() {
console.log(b);
}
return inner;
}
outer('I am param')(); // prints "I am param"
Closure can be formed with multiple hierarchies of methods.
function evenOuter() {
var val = 'From even outer';
function outer() {
function inner() {
console.log(val);
}
return inner;
}
return outer;
}
evenOuter()()();
Closure took the scoped variable and ignore the upper lexical scope,
var val = 'Global scope';
function outer() {
function inner() {
console.log(val);
}
var val = 'Outer scope';
return inner;
}
outer()(); // prints 'Outer scope'
By function currying, we can create new function for specialized argument and reuse them as needed.
function multiply(a) {
return function(b) {
return a * b;
}
}
// Currying the multiply function
const double = multiply(2);
const triple = multiply(3);
console.log(double(5)); // Output: 10
console.log(triple(5)); // Output: 15
Higher order function takes another function as a parameter.
function repeat(fn, n) {
return function(x) {
for (let i = 0; i < n; i++) {
fn(x);
}
}
}
function logWithPrefix(prefix) {
return function(message) {
console.log(`${prefix}: ${message}`);
}
}
const repeatLog = repeat(logWithPrefix('INFO'), 3);
repeatLog('Hello'); // Output: INFO: Hello (three times)
Similar to Function currying example.
Consider the following code,
let count = 0;
function increment() {
count += 1
console.log(count);
}
increment();
count = 2;
Here the major flow is, we can increment the count directly without using the increment method.
To ensure, always use the increment to increment the count, we can make use of closure.
function counter() {
let count = 0;
function increment() {
count += 1
console.log(count);
}
return increment;
}
const myIncrement = counter();
myIncrement(); // print 1
myIncrement(); // print 2
An interesting fact is, every time we call the counter method, it always creates a new session.
function counter() {
let count = 0;
function increment() {
count += 1
console.log(count);
}
return increment;
}
const myIncrement1 = counter();
myIncrement1(); // prints 1
myIncrement1(); // prints 2
const myIncrement2 = counter();
myIncrement2(); // prints 1
myIncrement2(); // prints 2
If we need another function, decrement then the code snippet is not scalable. In this case, we can make use of Function Constructor.
function Counter() {
let count = 0;
this.increment = function() {
count += 1
console.log(count);
}
this.decrement = function () {
count -= 1;
console.log(count)
}
}
const myCounter = new Counter();
myCounter.increment(); // print 1
myCounter.increment(); // print 2
myCounter.decrement(); // print 1
If not handled properly,