“This is the third day of my participation in the First Challenge 2022. For details: First Challenge 2022”
JavaScript Advanced Programming (Version 3)
Closures are functions that have access to variables in the scope of another function.
The Definitive JavaScript Guide (6th edition)
Function objects can be related to each other through scope chains, and variables within the body of a function can be stored in the scope of the function, a property known in the computer science literature as closures.
The definitions of closures vary, and they are a little tricky to understand. All of these definitions are fine when we’re trying to state what a closure is. State what you think is the most correct definition, and then explain your statement through the application of closures
I briefly looked at the Function Definitions link in ES6
You can see that the Closure it defines is returned by the internal FunctionCreate
Let me give you my understanding of closures ——
First: Closures have two parts:
- function
- The variable of the lexical environment in which the function resides
- By definition: the creation of a function forms a closure
- A function that refers to a variable in its lexical context exists even if the lexical context does not exist
Insert your own thoughts:
- Put aside
closure
This gadget, under normal circumstances, after a function to perform, it will destroy the function of internal variables, but in practice there are many possible we also need to use these variables should be destroyed, such as the function returns a function (variable) refers to the outer function, this time we need to make the variables exist, so was bornclosure
. The closure was created when the function was created because there were so many possibilities - Function execution isThe stackStructure when executedInto the stack, no further action is required.Out of the stackWhen the function executes, it carries
closure
Variables that are referenced in the stack
function fooWrapper() {
var x = 0
function foo() {
var xx = 1
function fooInner() {
var xxx = 2
debugger
console.log(x)
console.log(xx)
return xx
}
fooInner()
}
foo()
}
Copy the code
Open and execute the code above in the browser console: see the call stack and the variables it contains,
FooWrapper, foo, and fooInner are stacked, and variables in the scope of the stack can be seen in local, global, and the variables in the closure they carry
Application of closures
The definition of closures is really mysterious and mysterious. For a deep understanding of closures, it is better to focus on the application of closures
Closures are used everywhere
function foo() {
var a = 1
return function () {
a++
console.log(a)
return a
}
}
var getA = foo()
getA() / / 2
getA() / / 3
Copy the code
The above example is not very common for us, we often have this kind of situation in writing code, in addition to interview questions
In an interview, of course, this will happen again
var getA = foo()
getA() / / 2
getA() / / 3
var getB = foo()
getB() / / 2
Copy the code
Because when Foo executes again, a new closure is formed
Examples of this are the most basic features of closures: caching data, variable persistence, and ultimately, the variables inside the closure are active and can always be referenced
Let’s see how closures are used
Different processing is done by caching closure variables
- Application of single column pattern
Let’s take a simple example
// Check if you are in love
function inLove() {
// You are the only single dog
const persons = ['Single Dog']
function addPerson() {
persons.push('Single Dog')}return {
addPerson,
getRes: function () {
return persons.length > 1}}}const love = inLove()
love.addPerson()
love.getRes()
love.addPerson()
love.getRes()
Copy the code
Example above: if one person is single, if another single dog comes along, you are a couple, and the next one is still a couple…
When an instance is instantiated for the first time in the singleton class, it is given a value. If it exists, the generated instance is not returned
class SingletonApple {
constructor(){}static getInstance() {
if(!this.instance) {
this.instance = new SingletonApple();
}
return this.instance; }}Copy the code
Simulate block scope
- A classic interview question
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i)
}, i * 1000)}Copy the code
Print out five 5’s in turn
I want to print every I (0, 1, 2, 3, 4) at once. How do I rewrite that
Of course you can just let
Let’s look at it in the form of closures
for (var i = 0; i < 5; i++) {
(function(i) {
setTimeout(function() {
console.log(i)
}, i * 1000)
})(i)
}
Copy the code
We simply pass in the I of our current loop through a self-executing function (IFFE)
First of all, before rewriting, our setTimeout is delayed, the loop body executes normally, and setTimeout will be executed after the loop is completed. At this time, I is a global variable and has been set to the value 5 after the loop, so it is ok to use let. Through closure, we form our scope, and I is passed in as a parameter. I here is the value of I for the current loop
As an extension we can do event binding for node loops
Get a set of DOM node loops and bind it to a function that uses the variable I in the function as well
The function is currified
- Function corrification refers to changing one function that takes n arguments to n nested functions that take only one argument
Let’s steal an example
function getAddress(province, city, area) {
return province + city + area
}
getAddress('jiangsu'.'wuxi'.'Lakeside')
Copy the code
Let me rewrite this by the Definition of Corritization
function getAddress(province) {
return function (city) {
return function(area) {
return province + city + area
}
}
}
getAddress('jiangsu') ('wuxi') ('Lakeside')
Copy the code
Experience the benefits
var province = getAddress('jiangsu')
var wuxi = province('wuxi')
// At this time I want to acquire Nanjing
var city = province('nanjing')
var area = city('Basalt')
Copy the code
Does the closure feel a little bit better at this point
Partial function
- The partial function is actually an upgrade of the Curryization, it does not have the curryization limit of 1 parameter, depending on the actual situation n parameters can be arbitrarily passed in multiple parameters at a time
Let’s move on to the next classic interview question
Implement the following method add(1) (2) (3) = 6;
add(1.2.3) (4) = 10;
add(1) (2) (3) (4) (5) = 15;
Copy the code
function add() {
var arg = [... arguments]
var calc = function () {
var newArg = [... arguments]
if(newArg.length) { arg.push(... newArg)return calc
} else {
return arg.reduce((cur, next) = > cur + next, 0)}}return calc
}
add(1) (2) (3.4) ()/ / 10
Copy the code
What if I were to write a Coriolization function
function currying(fn, length) {
length = length || fn.length
return function (. args) {
return args.length >= length
? fn.apply(this, args)
: currying(fn.bind(this. args), length - args.length) } }Copy the code
Modular applications
Closure view links are used in es6’s Module
Let me give you a simple example
function createModule() {
var x = 1,
y = 2
z = 3
return {
x,
y,
z,
add(fish) {
return x + y + z + fish
}
}
}
exportModule = createModule()
exportModule.x
exportModule.y
exportModule.add('salted fish')
Copy the code
For WebPack, these packaging tools are all in the form of closures posted below: Closure Application 6 – The builder packs Webpack
The problem with closures causing memory leaks
Overusing closures can cause closure variables not to be collected by the garbage collection mechanism. The common case for using closures is a memory leak, which can occur when there is too much nesting and layers of closure variables are active
For more on the recycling mechanism of closures, check out Masami Seto’s article on how each browser handles different engines
conclusion
Sensory closures are a thing that came into being, they’re everywhere, and based on them there are a lot of applications and a lot of ways to write code, and based on the knowledge of closures, it’s even more critical to learn what they’re derived from.