Closure: A term thrown around a lot when talking about JavaScript. Sometimes in interesting ways, other times in alienating ways. Rather than get mathy (I'd fail), I'll describe closures in the terms I use to understand them. Also, a lil' code snip.
A closure is a function that captures the state that it’s surrounded by, closing over said state.
(function(first) {
return function(second) { // this function is a closure
return first + second;
}
}(1)(1));
Uh, what do closures do…
Closures let us write code with a higher level of abstraction. A good thing, as abstraction allows us to solve more problems with less code. Now, by example. Let’s write a baby program that counts the occurrence of a particular word in a sentence.
var str = `these are some words that i want to search for a thing, and i am
searching, yea, searching`.match(new RegExp('thing')).length;
Works, pay me. But wait! What if our programs frequently needs to count words in sentences? Sounds like a task for a function:
var counter = function(wordToCount, findIn) {
return findIn.match(new RegExp(wordToCount, 'g')).length;
};
Alright, okay. But wait! Our function requires two arguments when we call it. What if we don’t know the string that we’d like to search at this point in our program? We can abstract this a bit more with closures. Let’s build a function that returns another function.
var counter = function(wordToCount) {
return function(findIn) { // an closure, a closure.
return findIn.match(new RegExp(wordToCount, 'g')).length;
}
}
Closures “know” about the variables defined in their enclosing scope. This has
some interesting consequences when creating functions that return functions.
In the last snip, counter
contains a function that we can call
like:
var countTheWordSup = counter('sup');
We’ve assigned the value returned by counter()
to a new variable.
That returned value happens to be another function, so
countTheWordSup
essentially becomes the name of a function. Let’s
call it:
countTheWordSup('sup hi hey up up hi sup hellowww'); // 2
As if by magic, countTheWordSup()
remembers the value we passed
to counter()
as “wordToCount”. Closure by example.
The Module Pattern
I made a trick on you! I’ve conflated closures with curried functions, as curried functions are what made closures really click for me. Closures are also visible in what is commonly referred to as the module pattern, which is perhaps a more typical introduction to closures.
The module pattern leverages closures to approximate private and public variables in classical languages:
var uh = function() {
var closed = 'hi';
return {
foo: function() {
console.log(closed);
}
};
};
var hello = uh();
hello.foo();
The function uh
returns an object, a property on which is a function that
references a variable in uh
’s scope. The same mechanism is at
work, though to a different end; here, we’re doing a bit of data hiding.
There’s quite a bit more to closures, but this introduction should give you enough utility that you’ll continue to explore other usages.
Originally published on the VictorOps blog