What is a JavaScript closure?
This article is reproduced from: Zhongcheng translation
Translator: Mcbai
Links: http://www.zcfy.cc/article/4639
Original: https://medium.freecodecamp.org/whats-a-javascript-closure-in-plain-english-please-6a1fc1d2ff1c
JavaScript closures are like the function of a car--different locations have different components that correspond to that car.
Each of the functions in JavaScript forms a closure, which is one of the coolest features of JavaScript. Because there is no closure, it can be difficult to implement a public structure such as a callback function or an event handle.
Whenever you define a function, you create a closure. Then when you execute these functions, their closures allow them to access the data within their scope.
It's kind of like producing a car with some kind start
accelerate
decelerate
of features like that. The drivers perform these functions every time they manipulate their car. Closures that define these functions are like cars, and ' close ' the variables that need to be manipulated.
Let's take accelerate
a simple analogy with the function, which is defined when the car is made:
function accelerate(force) { // Is the car started? // Do we have fuel? // Are we in traction control mode? // Many other checks... // If all good, burn more fuel depending on // the force variable (how hard we’re pressing the gas pedal)}
Each time the driver stepped on the throttle, the method was executed. Note that this function requires access to a number of variables to execute, including its own force
variables. But more importantly, it needs its own variables that are controlled by other car functions outside its own domain. This is the usefulness of the closure of the accelerate
function (which we get from the car itself).
The following are the accelerate
commitments made by the function's closure to the function 加速
:
> Well accelerate
, when you do, you can access your _force_
variables, you can access _isCarStarted_
variables, and you can access variables _fuelLevel_
and _isTractionControlOn_
variables. You can also control the variables that we send to the engine _currentFuelSupply_
.
Note that closures do not give these variables the acceleration
exact value of the function, but rather allow accelerate
access to the values when the function executes.
Closures are closely related to function scopes, so understanding how these scopes work will help to understand closures. In short, the most important thing to know about scopes is to understand the process by which a private function scope is created and used to execute the function when you execute a function.
Then, when your inner function starts executing functions, these function scopes become nested.
When you define a function, you create a closure, not when you execute it. Then, whenever you execute this function, its already defined closure allows it to access all the function scopes available to it.
In a way, you can assume that the scope is temporary (except for the global scope) and that the closure is permanent.
A closure shown by a Chrome debugging tool.
To really understand the role of closures in JavaScript, you first need to understand a few simple JavaScript functions and scope concepts.
Before we get started, notice that I've created an interactive experiment that you can look at here.
1?—? assigning functions by reference
When you assign a function to a variable, it looks like this:
function sayHello() { console.log("hello");};var func = sayHello;
You are assigning func
a reference to a variable instead sayHello
of copying it. This makes func
just sayHello
an alias, and anything you do on that alias is actually manipulated on the original function. Like what:
func.answer = 42;console.log(sayHello.answer); // prints 42
The properties answer
are set directly func
on the and then used sayHello
for reading, which is still valid.
You can also perform aliases by executing func
sayHello
:
func() // prints "hello"
2?—? Scope has a life cycle
When you invoke a function, a scope is created during the execution of the function, the function finishes, and the scope disappears.
When you call the function for the second time, a new, different scope is created during the second execution, and the second scope disappears as soon as the function finishes executing.
function printA() { console.log(answer); var answer = 1;};
printA(); // this creates a scope which gets discarded right after
printA(); // this creates a new different scope which also gets discarded right after;
The two scopes created in the previous example are different. The variables here are answer
completely unshared between the two of them.
Each function scope has a life cycle. They are created and then discarded at once. The only exception is the global scope, which does not disappear as long as the application is running.
3?—? closures span multiple scopes when you define a function, you create a closure
Unlike scopes, closures are created when you define a function, not when you execute a function. Closures do not disappear after you have finished executing the function.
After defining a function for a long time, you can still access the data in the closure, even if it executes.
A closure contains all the books that a defined function can access. This means defining the scope of the function, the scope of the global scope and the scope of the defined function, and the global scope itself.
var G = ‘G‘;// Define a function and create a closurefunction functionA() { var A = ‘A‘ // Define a function and create a closure function functionB() { var B = ‘B‘ console.log(A, B, G); } functionB(); // prints A, B, G // functionB closure does not get discarded A = 42; functionB(); // prints 42, B, G}functionA();
When we define a functionB
created closure, we allow access to scopes functionB
, scopes, functionA
and global scopes.
Each time we execute functionB
, we can access the variables through the previously created closures, B
A
and G
. However, closures do not replicate these variables, but instead refer to them.
For example, functionB
after a closure has been created, the A
value of the variable will change at some point, and when we do functionB
, we will see the new value instead of the old value. functionB
the second call to print 42、B、G
, because A
the value of the variable is changed to 42
, the closure provides us with a reference, not a copy.
Do not confuse closures and scopes
It is common to confuse closures with scopes, so let's make sure not to do so.
// scope: globalvar a = 1;void function one() { // scope: one // closure: [one, global] var b = 2; void function two() { // scope: two // closure: [two, one, global] var c = 3; void function three() { // scope: three // closure: [three, two, one, global] var d = 4; console.log(a + b + c + d); // prints 10 }(); }();}();
In the simple example above, we defined and immediately called three functions, so they all created scopes and closures.
The scope one()
of the function is itself, and its closure gives us the right to access it and global scope.
The scope of the function two()
is itself, and its closures let us have access to it and functions one()
, as well as the global scope of the right.
Similarly, three()
the closure of a function gives us the power to access all scopes. That's why we can three()
access all the variables in the function.
But the relationship between scopes and closures is not always the case. When you define and invoke functions in different scopes, the situation becomes dissimilar. Let me explain by an example:
var v = 1;var f1 = function () { console.log(v);}var f2 = function() { var v = 2; f1(); // Will this print 1 or 2?};f2();
Do you think the above example will print 1
or not 2
? The code is simple, f1()
and v
the function prints a value that is 1 of the global scope. But we do it in a function that has a different value equal to 2 v
f2()
f1()
, and then executes it f2()
.
Will this code print 1 or 2?
If you want to say 2, then you will be surprised that this code actually prints 1. The reason is that scopes and closures are not the same. The console.log
method uses the closure that is created when we define f1()
f1()
it, which means that f1()
the closure value allows us to access f1()
and scope the global.
The f1()
scope of the place we perform does not affect closures. In fact, f1()
closures do not give us the power to access function scopes f2()
. If you delete the global variable and v
then execute the code, you will get an error message:
var f1 = function () { console.log(v);}var f2 = function() { var v = 2; f1(); // ReferenceError: v is not defined};f2();
This is important for understanding and remembering.
4?—? closures have read and write permissions
Since closures give us references to variables in scope, it means that they give us permission to read and write, and not just read.
Take a look at this example:
function outer() { let a = 42; function inner() { a = 43; } inner(); console.log(a);}outer();
We define a inner()
function that creates a closure that allows us to access variables a
. We can read and write this variable, and as we have really changed its value, we change outer()
a
the value of the variable in the scope.
This code will print 43 because we inner()
have changed the outer()
function's variables with the closure of the function.
That's why we can change global variables everywhere. All closures provide us with read and write access to all global variables.
5?—? closures can share scopes
Because closures give us the power to access nested scopes when defining functions, so when we define multiple functions in the same scope, the scope is shared by the closures. For this reason, the global scope is always shared by all closures.
function parent() { let a = 10; function double() { a = a+a; console.log(a); }; function square() { a = a*a; console.log(a); } return { double, square }}let { double, square } = parent();double(); // prints 20square(); // prints 400double(); // prints 800
In the above example, we have a function that sets the value of the variable a
to 10 parent()
, and we parent()
define two functions in the scope of the function, double()
and square()
. Defines the double()
scope of the function and the square()
closure shared function that is created when it occurs double()
.
Because double()
and square()
will change a
the variables, when we execute the last 3 lines of code, we first add a
(Let a
= 20), and then multiply the added value (Let a
= 400), and then add the multiplied value (let a
= 800).
One last Test
Let's test your understanding of closures so far. Before you execute the following code, guess what it will print:
let a = 1;const function1 = function() { console.log(a); a = 2}a = 3;const function2 = function() { console.log(a);}function1();function2();
I hope to get the right answer and hope that this simple concept will help you understand the important role that function closures play in JavaScript.
What is a JavaScript closure?