The scope chain and variable object are introduced earlier. Now it is easy to understand the closure. Actually, we have all talked about closures.
The scope chain and variable object are introduced earlier. Now it is easy to understand the closure. In fact, we have all talked about closures. However, we should try to discuss the closure from a theoretical point of view to see how the closure in ECMAScript actually works.
Before directly discussing the ECMAScript closure, it is necessary to take a look at some basic definitions in functional programming.
As we all know, in Functional Languages (ECMAScript also supports this style), functions are data. For example, a function can be assigned a value to a variable. When a parameter is passed to another function, it can also be returned from the function. Such functions have special names and structures.
Definition
A functional argument ("Funarg")-is an argument which value is a function.
Function parameter ("Funarg") -- refers to the parameter whose value is a function.
Example:
function exampleFunc(funArg) { funArg();}exampleFunc(function () { alert('funArg');});
In the above example, the actual parameter funarg is actually an anonymous function passed to exampleFunc.
In turn, a function that accepts a function-type parameter is called a high-order function (HOF ). It can also be called a function or partial mathematical or operator. In the above example, exampleFunc is such a function.
Previously mentioned, a function can be used not only as a parameter but also as a return value. These functions return values are called functions with function values (functions with functional value or function valued functions ).
(function functionValued() { return function () { alert('returned function is called'); };})()();
Functions that can exist in the form of normal data (for example, when a parameter is passed, a function-type parameter is accepted or returned with a function value) are called first-class functions (generally the first-class objects ). In ECMAScript, all functions are the first class objects.
A function can exist as a normal data (for example, when a parameter is passed, a function-type parameter is accepted or returned as a function value ).
In ECMAScript, all functions are the first class objects.
A function that accepts itself as a parameter is called an auto-applicative function or self-applicative function ):
(function selfApplicative(funArg) { if (funArg && funArg === selfApplicative) { alert('self-applicative'); return; } selfApplicative(selfApplicative);})();
Auto-replicative function or self-replicative function ). Generally, the word "self-replication" is used in literature:
(function selfReplicative() { return selfReplicative;})();
One of the more interesting modes of the auto-copy function is to accept only one item of the set as a parameter, instead of accepting the set itself.
// Receives the function registerModes (modes) {modes. forEach (registerMode, modes);} // use registerModes (['roster', 'accounts', 'groups']); // function modes (mode) declared by the self-replication function) {registerMode (mode); // register a mode return modes; // return the function itself} // usage, modes chained call modes ('roster') ('accounts ') ('groupup') // a bit similar: jQueryObject. addClass (""). toggle (). removClass ("B ")
However, directly transferring a set is relatively effective and intuitive.
Variables defined in functional parameters can be accessed when "funarg" is activated (because the variable object storing context data is created every time it enters the context ):
Function testFn (funArg) {// when funarg is activated, the local variable localVar can access funArg (10); // 20 funArg (20 ); // 30} testFn (function (arg) {var localVar = 10; alert (arg + localVar );});
However, in ECMAScript, a function can be encapsulated in the parent function and can use variables in the context of the parent function. This feature causes funarg problems.
Funarg Problems
In a stack-oriented programming language, Partial Variables of a function are stored on the stack. Each time a function is activated, these variables and function parameters are pushed onto the stack.
When the function returns, these parameters are removed from the stack. This model imposes great restrictions on using a function as a function type value (for example, returning a function as a return value from the parent function ). In most cases, the problem occurs when the function has a free variable.
A free variable is a variable used in a function. It is neither a function parameter nor a local variable of the function.
Example:
function testFn() { var localVar = 10; function innerFn(innerParam) { alert(innerParam + localVar); } return innerFn;}var someFn = testFn();someFn(20); // 30
In the above example, localVar is a free variable for the innerFn function.
For systems that use the stack-oriented model to store local variables, this means that when the testFn function call ends, its local variables will be removed from the stack. In this way, when the innerFn function is called from outside, an error occurs (because the localVar variable does not exist ).
Moreover, in the stack-oriented implementation model, it is impossible to return innerFn with a returned value. Because it is also a local variable of the testFn function, it will be removed with the return of testFn.
Another problem is when the system uses dynamic scopes and functions as function parameters.
Take the following example (pseudo code ):
Var z = 10; function foo () {alert (z);} foo (); // 10-When static and dynamic scopes are used (function () {var z = 20; foo (); // 10-use static scope, 20-use dynamic scope })(); // when using foo as a parameter, it is the same (function (funArg) {var z = 30; funArg (); // 10-static scope, 30-dynamic scope }) (foo );
We can see that the system using dynamic scopes and variables (identifiers) are managed through the dynamic stack of variables. Therefore, free variables are queried in the current active dynamic chain, rather than in the static scope chain saved during function creation.
In this way, a conflict occurs. For example, even if Z still exists (opposite to the previous example of removing a variable from the stack), there is still a problem: in different function calls, which of the following is the value of Z (from which context and scope )?
The above describes two types of funarg problems-depending on whether the function is returned as a return value (the first type of problem) and whether the function is used as a function parameter (the second type of problem ).
To solve the above problem, the concept of closure is introduced.
Closure
Closure is the combination of a code block and Context data that creates the code block.
Let's take a look at the following example (pseudo code ):
Var x = 20; function foo () {alert (x); // free variable "x" = 20} // fooClosure = {call: foo // reference to function lexicalEnvironment: {x: 20} // context of the Search context };
In the preceding example, "fooClosure" is a pseudo-code. Correspondingly, in ECMAScript, the "foo" function already has an internal Attribute-create the scope chain of the context of the function.
"Lexical" is usually omitted. In the preceding example, Context data is saved when the closure is created. When the function is called next time, the free variable can be found in the saved (closure) context. As shown in the code above, the value of the variable "z" is always 10.
In the definition, we use the generalized word "code block". However, we usually use functions that we often use (in ECMAScript. Of course, not all implementations of the closure will bind the closure with the function. For example, in Ruby, the closure may be a procedure object ), A lambda expression or code block.
Stack-based implementation is obviously not applicable to the implementation of saving local variables after the context is destroyed (because it is in conflict with the stack-based structure ). Therefore, in this case, the closure data in the upper-level scope is implemented by dynamically allocating memory (based on the implementation of "heap"), and the garbage collector (GC) is used together) and reference counting ). This implementation method has lower performance than stack-based implementation. However, any implementation can always be optimized: You can analyze whether a function uses free variables, function parameters, or function values, then decide whether to store data in the stack or heap based on the situation.
Additional reading
The topic list of this article is as follows:
- How should we understand the working principle of the JavaScript engine?
- JavaScript exploration: the importance of writing maintainable code
- JavaScript exploration: exercise caution when using global variables
- JavaScript exploration: var pre-parsing and side effects
- JavaScript exploration: for Loop (for Loops)
- JavaScript exploration: for-in loop (for-in Loops)
- Exploring JavaScript: Prototypes is too powerful
- JavaScript: eval () is the devil"
- JavaScript exploration: Using parseInt () for Numerical Conversion
- Exploring JavaScript: Basic coding specifications
- JavaScript exploration: function declaration and function expression
- JavaScript exploration: Name function expressions
- JavaScript: function name in the debugger
- JavaScript: JScript Bug
- JavaScript exploration: Memory Management of JScript
- Exploring JavaScript: SpiderMonkey's quirks
- JavaScript exploration: an alternative solution to naming function expressions
- JavaScript exploration: Object
- JavaScript exploration: Prototype chain
- JavaScript exploration: Constructor
- JavaScript probing: executable context Stack
- Execution context 1: Variable object and activity object
- Execution context 2: Scope chain Scope Chains
- Execution context 3: Closure Closures
- Execution context 4: This pointer
- Exploring JavaScript: Powerful prototype and prototype chain
- JavaScript Functions 1: function declaration
- JavaScript function 2: function expressions
- JavaScript function 3: function expressions in a group
- JavaScript function 4: function Constructor
- JavaScript variable object 1: VO Declaration
- JavaScript variable object 2: VO in different execution contexts
- JavaScript variable object 3: two stages of execution Context
- JavaScript variable object IV: Variables
- Property of the JavaScript variable object __parent _
- JavaScript scope chain 1: Scope chain Definition
- JavaScript scope chain 2: function Lifecycle
- JavaScript scope chain 3: Scope chain features
- JavaScript closure 1: Introduction to closures
- JavaScript closure 2: Implementation of closure
- JavaScript closure 3: Closure usage
Address: http://www.nowamagic.net/librarys/veda/detail/1707,welcome.