JavaScript closure 1: Introduction to closures

Source: Internet
Author: User
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:

  1. How should we understand the working principle of the JavaScript engine?
  2. JavaScript exploration: the importance of writing maintainable code
  3. JavaScript exploration: exercise caution when using global variables
  4. JavaScript exploration: var pre-parsing and side effects
  5. JavaScript exploration: for Loop (for Loops)
  6. JavaScript exploration: for-in loop (for-in Loops)
  7. Exploring JavaScript: Prototypes is too powerful
  8. JavaScript: eval () is the devil"
  9. JavaScript exploration: Using parseInt () for Numerical Conversion
  10. Exploring JavaScript: Basic coding specifications
  11. JavaScript exploration: function declaration and function expression
  12. JavaScript exploration: Name function expressions
  13. JavaScript: function name in the debugger
  14. JavaScript: JScript Bug
  15. JavaScript exploration: Memory Management of JScript
  16. Exploring JavaScript: SpiderMonkey's quirks
  17. JavaScript exploration: an alternative solution to naming function expressions
  18. JavaScript exploration: Object
  19. JavaScript exploration: Prototype chain
  20. JavaScript exploration: Constructor
  21. JavaScript probing: executable context Stack
  22. Execution context 1: Variable object and activity object
  23. Execution context 2: Scope chain Scope Chains
  24. Execution context 3: Closure Closures
  25. Execution context 4: This pointer
  26. Exploring JavaScript: Powerful prototype and prototype chain
  27. JavaScript Functions 1: function declaration
  28. JavaScript function 2: function expressions
  29. JavaScript function 3: function expressions in a group
  30. JavaScript function 4: function Constructor
  31. JavaScript variable object 1: VO Declaration
  32. JavaScript variable object 2: VO in different execution contexts
  33. JavaScript variable object 3: two stages of execution Context
  34. JavaScript variable object IV: Variables
  35. Property of the JavaScript variable object __parent _
  36. JavaScript scope chain 1: Scope chain Definition
  37. JavaScript scope chain 2: function Lifecycle
  38. JavaScript scope chain 3: Scope chain features
  39. JavaScript closure 1: Introduction to closures
  40. JavaScript closure 2: Implementation of closure
  41. JavaScript closure 3: Closure usage

Address: http://www.nowamagic.net/librarys/veda/detail/1707,welcome.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.