“Writing in JS language without understanding closure is like writing Java without understanding classes” — Douglas Crockford, father of JSON
You've been working as a junior developer for awhile, and you're finally ready to apply for your next developer job.
You're sitting at the interview and it's going well. You know Javascript pretty well.
Then they ask, "Explain the topic of closures"
You freeze. Your heart starts beating faster. You blurt out "is it hot in here or is it just me?"
The interviewer looks puzzled at you.
One drop of sweat collects on your forehead and slowly rolls down. Right into your eye.
Now you're squinting at the interviewer. You then start worrying if he thinks you're winking at him profusely.
You (attempt to) channel your inner Beyonce, but you end up looking like an absolute clown.
Your friend Felicia asks you how the interview went.
This. This is how it went Felicia.
What was the point of that story?
I'm not sure. But let's talk about closures.
Closures is one of those topics that scares people, but there is no reason to be.
People often overexplain it, making it sound more complicated than it is.
We can also do some cool stuff with it, like emulating private methods.
Example:
let x = 0;
const addNumber = () => {
return 3 + x;
}
console.log(addNumber);
Why is this not efficient?
It uses global scope, and there is nothing to protect it against change.
We often forget that javascript is a lexical scoping
language. That's a really snobby way of saying that inheritance flows inwards
A variable outside a function is available for use within a function, but not the other way around.
You can not use a variable inside a function, outside it.
function outside() {
let x = 2;
return function inside(y) {
return x * y;
}
}
If we call outside()
what do we get?
When we call outside()
, we get another function returned, in this case inside
What if we call outside()(4)
we pass in 4 to the inside
function.
outside()(4)
// 8
The double parenthesis looks weird, so some people like this way better:
const myClosureFunction = outside();
myClosureFunction(5)
// 10
myClosureFunction(5) === outside()(5)
// true
Source: A Beginner’s Guide to Understanding JavaScript Closures
The best part of a closure is
x
, because we have created a variable that no other part of our program can touch, but we can still use.This is the power of closures: it lets us create values that can’t be altered or accessed by any functions other than the closure itself.
The reason this works is because scopes can access values in their parents, but not their children. x is defined in the parent scope of inside, so inside can still access it and multiply it by y.
However, the only thing that gets exposed to the global scope is the definition of inside, not the variable x.
That means in our entire program, the only way we can interact with x is by using the closure.
Non-closure Example:
let x = 2 //global scope
function inside(y) {
return x * y //taking x from global
}
inside(4)
// 8
// We can alter x
x = 5
inside(4)
//20
Closure Example:
function outside() {
let x = 2;
return function inside(y) {
return x * y;
}
}
const myClosureFunction = outside();
myClosureFunction(5)
// 10
x = 4
myClosureFunction(5)
// 10
// Notice how it's still 10. The x inside the closure is different than the x outside
x
is defined in our outside
function, so anything outside can not reach down into it and change it.
When we tried to reassign x
to the value 4, JS saw that as a completely different x
.
function adder(x) {
return function(y) {
return x + y
}
}
let add5 = adder(5);
let add10 = adder(10);
console.log(add5(2)); // 7
console.log(add10(2)); // 12