What is a "closure"?
A closure is the combination of a function enclosed with references to its surrounding state (lexical environment). It gives you access to an outer function's scope or environment from an inner function.
Consider the following code snippet:
function outerFunction() {
let innerVar = "I'm inside outerFunction";
function innerFunction() {
console.log(`${innerVar}, but I can be accessed from innerFunction too!`);
}
innerFunction();
}
outerFunction();
// > "I'm inside outerFunction, but I can be accessed from innerFunction too!"
Lexical Scope/Environment
In the above code snippet, outerFunction
creates a variable called innerVar
, and a function called innerFunction
. The innerFunction
function is enclosed inside, and is only available within, outerFunction
. innerFunction
has no local variables of its own, but is able to access innerVar
because they are both within the lexical scope of outerFunction
.
Closure
In the initial code snippet, we called innerFunction
immediately after declaring it. But what if we return
the inner function instead?
function outside() {
let myName = 'Pixi';
function inside() {
alert(myName);
}
return inside;
}
let insideOutside = outside();
insideOutside();
If we run this code, we'll get an alert with my name. But why?
The reason this works is because functions in JavaScript form closures. A closure is a combination of a function and the lexical scope within which the function was declared.
insideOutside
becomes a reference to an instance of our inside
function when outside
is run. This instance of inside
maintains a reference to its lexical scope, which allows it to maintain its reference to the myName
variable.
Passing Arguments
We can use closures to our advantage in creating enclosed functions that accept arguments.
/* we create a function that accepts one argument,
and returns a function that also accepts one argument,
and utilizes both arguments... */
function makeMultiplier(x) {
return function (y) {
return x * y;
};
}
/* we can call the outer function
and assign it to a variable */
let multiplyBy2 = makeMultiplier(2);
let multiplyBy5 = makeMultiplier(5);
console.log(multiplyBy2(3)); // 6
console.log(multiplyBy5(3)); // 15
/* we can also use argument chaining to call
both functions at once */
console.log(makeMultiplier(2)(3)); // 6
console.log(makeMultiplier(5)(3)); // 15
Our new makeMultiplier
function gives us the ability to create more functions and then use those functions later.
When we create multiplyBy2
, the reference to x = 2
becomes a part of the functions lexical scope. We can then use this function to multiply other numbers by 2. The same is true for multiplyBy5
.
When we use argument chaining, we simply call the inner function immediately by passing an argument to makeMultiplier
and immediately passing an argument to the function which it returns.
Want to learn more about scope in JavaScript?
Check out my previous post on scope and variable hoisting and let me know if you still have any questions! It might inspire a future blog post!
xx - Emily / TheCodePixi
External Resources: |
---|
MDN Closure Docs |
Top comments (11)
That insideoutaide then outside we inside gave me a headache. Im going to bed lol. Jk, great stuff. Thanks for helping me understand it a little more as well. 😁
Haha sorry! I thought the naming was kinda funny, but I can see how it might be confusing 🙈
Lol I was just kidding.
Thank you for the article.
I had always been using the concept, but never called it a "closure". I have it in my mind as a "function wrapper". It allows all my inner wrapped functions (and at times do have a lot of them) to use all the common variables I have already declared in the main outer function without having to pass them individually to each function and declare them again.
Are multi-level closures classified as something else or just call something like "nested closures"?
I'm honestly not sure 🤔 that might get more into specific scope than closure itself. But, for instance, let's say in my "inside outside" example, there was a local scope variable inside of
inside
, that would be inside the "closure" created by theinside
function. But I'm not sure if there's any kind of special term for that in terms of closures.Closures have always broken my brain a little bit 😅, but this explanation makes it quite clear! Thank you for sharing 😄.
Thank you Sandrico! I'm so glad this helped clear things up for you 🤗
I aways thought this concept was called a Factory pattern.
I've never heard that term before 🤔 I guess I'll have to look it up
Great explanation..Closures always confuse me..