JavaScript Closures

If the word closure is new word to you, take a deep breath. Ignore the overly complex Wikipedia definitions and relax. If you have been writing JavaScript, you have been writing closures for a long time, even if you hadn’t realized it.

Variable Scope

Before understanding closures, we need to understand variable scope in JavaScript. Every time a function is defined it has it’s own variable scope.

function myScope() {
/*
* This is the scope of myScope.
* All variables defined in here can be used inside
* the function, but not outside!
*/


var helloWorld = 'hello, world!';
console.log(helloWorld); // 'hello, world!'
}

console.log(helloWorld); // Error

Going further, functions in JavaScript can nest. When these functions nest, the child functions have access to what’s defined in the parent.

In this example, we nest a few self executing functions to see how this relationship works.

let a = 'a';
console.log(a); // 'a'

(()=> {
let b = 'b';
console.log(a, b); // 'a, b'

(()=> {
let c = 'c';
console.log(a, b, c); // 'a, b, c'

})();
})();

console.log(a, b, c); // ReferenceError: b is not defined

This works because function scopes in JavaScript are built to nest. When you call for a variable’s value, the interpreter simply keeps moving up the chain of scopes until it finds what it needs.

So, What’s a Closure.

Simple put, a closure is a function that has it’s own scope as well as the scope of it’s parent. Yup, all functions in JavaScript are closures!

Now, Why Should You Care

Just tacking a new name onto something you’ve been using already isn’t all that useful, so why are we here? Closures can be manipulated to solve countless arrays of interesting programming problems. In particular, they are fantastic for…

Code Organization

I don’t know about you, but I’ve never enjoyed reading math related code. I love logic, and the descriptive nature of math, but numbers, not so much. So functions like this, while understandable, would be much better served with some good old self documenting code.

function sqrt(x, guess) {
if(Math.abs(guess * guess - x) < 0.001) {
return guess;
}
else {
return sqrt(x, (guess + x / guess) / 2);
}
}

console.log(sqrt(100)); // 10.000000000139897

Your first instinct would probably be to make a few variables to isolate the results of certain math heavy statements.

function sqrt(x, guess) {
let isCorrect = Math.abs(guess * guess - x) < 0.001;
let improvement;

if(isCorrect) {
return guess;
}
else {
let improvement = (guess + x / guess) / 2;
return sqrt(x, improvement);
}
}

console.log(sqrt(100)); // 10.000000000139897

Though much easier to read, we have now introduced state to our function. While not too much of a big deal for such a small piece of logic, a more convoluted example may get very difficult to keep track of. In those cases it may be desirable to break things down into smaller functions in exchange for some added stability.

function sqrt(x) {
function iterate(guess) {
if (isCorrect(guess)) return guess;
return iterate(improve(guess));
}

function isCorrect(guess) {
return Math.abs(guess * guess - x) < 0.001;
}

function improve(guess) {
return (guess + x / guess) / 2;
}

return iterate(1);
}

console.log(sqrt(100)); // 10.000000000139897

Rather than keeping track of state throughout the call stack, we can now reason about our code in much smaller and declarative chunks.

Note: Because all JavaScript functions are closures, the child functions all have access to x, which is in the parent scope. We will return to this idea in just a bit.

The Bad News

Declaring nested functions is always dangerous and should be done with caution. Each function you declare is a new and unique object, carrying the risk of potential performance issues.

For example, our square root function could cripple an application if it needs to iterate over millions of items. Whenever iteration or performance in consideration, always be careful before nesting functions.

Function and Variable Privacy

The following code is what is commonly known as the Revealing Module Pattern in JavaScript. It was my first pattern, and still one of my favorites. Essentially it let’s you define object literals with private members.

let HelloWorld = (()=> {
let hello = 'Hello';
let world = 'world';

function speak() {
console.log(`${hello}, ${world}!`);
}

return {
speak: speak
};
})();

Closures are what make this tick. We use one self invoking function to create a new scope. And return only what we want to be public from that inner scope.

This way, Hello World has access to the speak function inside, but both hello and world are private.

Removing Redundant Function Arguments

Have you ever had a series of functions that pass each other arguments in a chain. You know, like this?

function foo(a, b, c, d) {
bar(a, b, c, d);
}

function bar(a, b, c, d) {
baz(a, b, c, d);
}

function baz(a, b, c, d) {
return a + b + c + d;
}

foo(1, 2, 3, 4); // 10

This is a clear indicator of one of two things. Your code requires state and belongs in a class or module like structure or you needs to share arguments within a parent function

Since closures let your functions access the parent’s scope, we can use this to cut down on redundant arguments.

function foo(a, b, c, d) {
function bar() {
baz();
}

function baz() {
return a + b + c + d;
}

bar();
}

foo(1, 2, 3, 4); // 10

This results in code that isn’t quite as brittle and redundant as before.

Preventing Collisions

The private nature of function scopes make closures prime candidates from avoiding global namespace hell.

Here, the hello variable is being overwritten in our main.js file. When your application includes many open source libraries, it’s possible to have variables in the global namespace that you may not be aware of.

// other-file.js

var speak = 'hello';


// main.js
console.log(speak); // 'hello'
var speak = 'caio';
console.log(speak); // 'caio'

This is where Immediately Invoking Function Expressions (IIFE) come in to play. Or, we can just call it a closure!

// other-file.js

var speak = 'hello';


// main.js

(()=> {
var speak = 'ciao';
console.log(speak); // 'ciao'
})();

console.log(speak); // 'hello'

Our new, similarly named, variable can now exist along side it’s counter part in the main JavaScript file.

Conclusion

Closures are an integral part of what makes JavaScript tick, and what make a vast number of patterns work as well. Understanding these strange functions can help you make more well informed decisions and lead to a more stable application.

Happy Coding