Closures = Your favourite Burger
A simple explanation to the make or break question in JS.
I remember bombing my first Javascript interview with style - I knew I was out of the gate when I couldn't explain what a Closure was. I absolutely knew what it was - but somehow was unable to put into words.
So, what is a Closure?
Closure
In my mind Closure = Burger - Yup - thats it and nothing else.
Don't believe me - read ahead and you will start believing in burgers - I mean Closures :)
Burger Preparation
What all is needed to make a burger in the first place.
- Bread (Wheat or White)
- Patty (Veg or Non-Veg)
- Side kicks (Onions, Ketchup, Mayo etc)
With that in mind - let's create our finger-licking in-house Closure aka burger.
let sideKicks = ['onions', 'ketchup', 'tomato slices', 'mayo'];
function burger(breadType) {
function patty(pattyType) {
return (
breadType +
' bread, with ' +
pattyType +
' patty,' +
' sprinkled with ' +
sideKicks.toString().replaceAll(',', ' - ')
);
}
return patty;
}
f patty has access to the global variables (sideKicks) and its own variable(pattyType).
Including this - It has access to the breadType that we pass to f burger - This exact line is what a closure is - It closes over its surrounding variables also known as lexical environment.
Trying to get my six packs on - so today's burgers will be a Wheat Chicken burger:
- Bread - Wheat
- Patty - Chicken
- Side kicks - onions, ketchup, tomato slices, mayo
With that, if we call the function:
var patty = burger('Wheat');
var burgerWithPatty = patty('Chicken');
console.log(burgerWithPatty);
//Output
Wheat bread, with Chicken patty, sprinkled with
onions - ketchup - tomato slices - mayo
That is one delicious burger. Yummmmm.
To get to the meat of it, do a console.dir on f burger and f patty .
console.dir(burger);
console.dir(patty);
We can see here fburger has in its scope:
- ingrediants
- global window object
f burger(breadType)
arguments: null
caller: null
length: 1
name: "burger"
prototype: {constructor: ƒ}
__proto__: ƒ ()
[[FunctionLocation]]: app.js:3
[[Scopes]]: Scopes[2]
0: Script {sideKicks: Array(4)}
1: Global {window: Window, self: Window, document: document, name: "", location: Location, …}
Whereas fpatty has in its scope:
- Closure (burger) {breadType: "Wheat"}
- ingrediants
- global window object
f patty(pattyType)
arguments: null
caller: null
length: 1
name: "patty"
prototype: {constructor: ƒ}
__proto__: ƒ ()
[[FunctionLocation]]: app.js:4
[[Scopes]]: Scopes[3]
0: Closure (burger) {breadType: "Wheat"}
1: Script {sideKicks: Array(4)}
2: Global {window: Window, self: Window, document: document, name: "", location: Location, …}
Well if you are still hungry - You could just do
var anotherBurgerWithPatty = patty('Veg');
In short - Closure is nothing but a patty which knows which type of bread is it enclosed by.
Next time somebody asks what a Closure is - counter question - which is their favourite burger?