Deep understanding of the JavaScript core (a) JavaScript kernel (the promotion of the master must read) _javascript skills

Source: Internet
Author: User
Tags closure comments types of functions
Suitable for readers: experienced developers, professional front-end staff.

Original author: Dmitry A. Soshnikov
Release time: 2010-09-02
Original: Http://dmitrysoshnikov.com/ecmascript/javascript-the-core/
Reference 1:http://ued.ctrip.com/blog/?p=2795
Reference 2:http://www.cnblogs.com/ifishing/archive/2010/12/08/1900594.html
The main combination of the above 2 masters of Chinese translation, the two pieces of the essence of the article are combined together.

Let's take a look at the concept of objects [object], which is also the most basic concept in ecmasript.

Objects Object
ECMAScript is a highly abstract object-oriented (object-oriented) language used to handle objects objects. Of course, there are basic types, but they need to be converted to object objects as necessary.

An object was a collection of properties and has a single prototype object. The prototype may is either an object or the null value.

Object is a collection of attributes and has a separate prototype object [prototype object]. This prototype object [prototype object] can be an object or a null value.
Copy Code
Let's give an example of the basic object, first of all we have to be clear that the prototype of an object is a reference to an internal [[prototype]] property.

In general, however, we use the __< internal property name >__ underscore to replace the parentheses, such as __proto__ (this is a specific implementation of the prototype concept, although not the standard, for some scripting engines such as SpiderMonkey.)
Copy Code code as follows:

var foo = {
X:10,
Y:20
};

The above code Foo object has two explicit properties [explicit own properties] and an __proto__ attribute [implicit __proto__ property] with an implicit type, pointing to the prototype of Foo.

Figure 1. A basic object that contains a prototype

Why do we need prototypes, let's consider the concept of a prototype chain to answer this question.
Prototype chain (Prototype chain)
The prototype object is also an ordinary object, and it is possible to have its own prototype, if a prototype object's prototype is not NULL, we call it a prototype chain (prototype chain).

A prototype chain is a finite chain of objects which are used to implemented inheritance and shared properties. The prototype chain is an object composed of A finite object chain is implemented by inheriting and sharing properties.

Imagine a situation where 2 objects, most of which are the same, only a small part of it, obviously, in a good design pattern, we need to reuse that part of the same, rather than repeatedly defining the same methods or attributes in each object. In a system based on class [class-based], these reusable parts are referred to as class inheritance – the same part is placed in class A, then Class B and Class C inherit from a and can be declared to have their own unique objects.

ECMAScript has no concept of class. However, the idea of reusing [reuse] is no different (in some respects, even more flexible than class-) and can be implemented by the prototype chain prototype chain. This inheritance is called delegation based inheritance-a delegate based on inheritance, or, more commonly, is called prototype inheritance.

Similar to class "A", "B", "C", in ECMAScript Create object class "A", "B", "C", and correspondingly, object "a" has a common part of object "B" and "C". Both objects "B" and "C" contain only their own attached properties or methods.

Copy Code code as follows:

var a = {x:10, calculate:function (z) {return this.x + This.y + z}}; var B = {y:20, __proto__: a}; var c = {y:30, __proto__: a}; Invoke inherited Methods B.calculate (30); 60c.calculate (40); 80

Does this look very simple? B and C can use the Calculate method defined in a, which is achieved by a prototype chain [prototype chain].

The principle is simple: if the Calculate method is not found in object B (that is, the Calculate property is not in Object B), then the prototype chain is searched. If the Calculate method is not found in the prototype of B, then a prototype is found along the prototype chain, traversing the entire prototype chain. Remember, once you find it, return the first property or method you find. Therefore, the first property found becomes an inherited property. If you go through the entire prototype chain and still do not find it, you will return to undefined.

Note that this value is in an inheritance mechanism, still pointing to the object it originally belonged to, rather than the object it belonged to when it was found on the prototype chain. For example, in the above example, THIS.Y is obtained from B and C instead of a. Of course, you also found out that This.x was taken from a, because it was found through the prototype chain mechanism.

If the prototype of an object is not displayed or defined, the default value of __prototype__ is Object.prototype, and Object.prototype also has a __prototype__, This is the end of the prototype chain, and is set to null.

The following diagram shows the inheritance relationship of the above a,b,c

Figure 2. Prototype chain

The prototype chain will typically be used in situations where an object has the same or similar state structure (same or similar states structure) (that is, the same set of attributes) and a different state value (different states values). In this case, we can use constructors (constructor) to create objects under specific patterns (specified pattern).
Constructors (constructor)
In addition to creating objects, the constructor (constructor) does another useful thing-automatically sets the prototype object (prototype objects) for the new object created. The prototype object is stored in the Constructorfunction.prototype property.

For example, we rewrite the previous example, using the constructor to create the object "B" and "C", then the object "a" acts as the "Foo.prototype" role:

Copy Code code as follows:

Constructors
function Foo (y) {
The constructor will create the object in a specific pattern: the object being created will have a "Y" attribute
This.y = y;
}

"Foo.prototype" holds a prototype reference to a new object
So we can use it to define inheritance and share properties or methods
So, as with the previous example, we have the following code:

Inherit property "X"
foo.prototype.x = 10;

Inheritance method "Calculate"
Foo.prototype.calculate = function (z) {
Return this.x + This.y + z;
};

Create "B" and "C" using Foo mode
var B = new Foo (20);
var c = new Foo (30);

Calling inherited methods
B.calculate (30); 60
C.calculate (40); 80

Let's see if we've used the expected attributes

Console.log (

b.__proto__ = = Foo.prototype,//True
c.__proto__ = = Foo.prototype,//True

"Foo.prototype" automatically creates a special property "constructor"
Point to A's constructor itself
Instances "B" and "C" can be identified by authorization and used to detect their own constructors

B.constructor = = Foo,//True
C.constructor = = Foo,//True
Foo.prototype.constructor = = Foo//True

B.calculate = = B.__proto__.calculate,//True
B.__proto__.calculate = = Foo.prototype.calculate//True

);

The preceding code can be expressed as the following relationship:

Figure 3. The relationship between constructors and objects

As you can see from the above diagram, each object has a prototype. Constructor Foo also has its own __proto__, which is Function.prototype, and Function.prototype's __proto__ points to Object.prototype. Again, Foo.prototype is just an explicit property, which is the __proto__ property of B and C.
The complete and detailed explanation of this question can be found in the 18th and 192 chapters of the uncle's upcoming translations. There are two parts: object-oriented programming. General Theory (OOP. The general theory describes different object-oriented paradigms and styles (OOP Paradigms and Stylistics), as well as comparisons with ECMAScript, object-oriented programming. ECMAScript implementation (OOP. ECMAScript implementation), which specifically describes object-oriented programming in ECMAScript.

Now that we know the basic principle of object, let's take a look at the program execution environment inside ECMAScript [Runtime programs execution]. This is what is commonly known as the "execution context stack" [execution contexts stack]. Each element can be abstracted as object. You may have found, yes, in the ECMAScript, almost everywhere you can see the object figure.

Execution context stack (Execution contexts stack)
There are three types of code in Ecmasscript: Global, Function, and eval.

The execution of each code needs to depend on its own context. Of course, the context of global may cover many instances of function and eval. Each call to the function is entered in the context of the function execution, and the values of the variables in the function are computed. Each execution of the Eval function also enters the context of the eval execution, determining where the value of the variable should be obtained.

Note that a function can produce an infinite context, because the invocation of one of the functions (even recursion) creates a new context.

Copy Code code as follows:

function foo (bar) {}
Calls the same function, which results in 3 different contexts at a time
(contains a different state, such as the value of the parameter bar)

Foo (10);
Foo (20);
Foo (30);

An execution context can activate another context, just as a function calls another function (or global context calls a global function), and then it is called on one layer at a later level. Logically, this implementation is the stack, which we can call the context stack.

A context that activates another context is called the caller (caller). The activated context is called the callee (callee). The callee may also be the caller (for example, a function called in the global context calls some of its own internal methods).

When a caller activates a callee, the caller suspends its own execution and then gives control to the callee. So this callee is put on the stack, called the context in progress [running/active execution contexts]. When the callee context is over, the control will be handed over to its caller again, and caller will continue in the place where it has just been suspended. After the end of this caller, other contexts will continue to be triggered. A callee can end its own context either by returning (return) or by throwing an exception (exception).

The following figure, all ECMAScript program execution can be considered as an execution context stack [execution contexts (EC) stacks]. The top of the stack is the context in which the activation is active.

Figure 4. Execution context Stack

When a program begins, it first enters the global execution context environment [global execution contexts], which is also the bottommost element in the stack. This global program begins initialization, initializing the necessary objects [objects] and functions [functions]. During this global context, it may activate some methods (of course, which have been initialized), then enter their context and then push the new elements onto the stack. After the initialization is over, the system waits for events (such as the user's mouse clicks), triggers some methods, and then enters a new context.

See Figure 5, there is a function context "Ec1″" and a Global Context "" Global EC ", the following figure shows the change of stack from the" Global EC "entry and exit Ec1″:

Figure 5. Changes to the execution context stack

This is how the ECMAScript runtime system manages the execution of code.

For the content of the ECMAScript execution context stack, please refer to the 11th chapter of the implementation context (Execution contexts) of this series of tutorials.

As mentioned above, each execution context in the stack can be represented as an object. Let's look at the structure of the context object and the state it needs to execute its code.
Execution contexts (Execution context)
An execution context can be abstracted as object. Each execution context has a series of attributes (which we call the context state) that they use to track the execution progress of the associated code. This diagram is the structure of a context.

Figure 6. Context structure

In addition to the 3 required properties (Variable object (variable object), the this pointer (this value), the scope chain (scope chain), the execution context can also have any additional attributes based on the specific implementation. Next, let's take a closer look at these three properties.

Variable objects (Variable object)
A variable object is a scope of the data related with the execution context.
It ' s a special object associated with the context and which stores variables and function declarations are being defined W Ithin the context.

The Variable object (variable object) is the scope of data that is related to the execution context.
It is a special object associated with the context that stores variables (variables) and function declarations (functions declarations) that are defined in the context.
Copy Code
Note: functional expression [function expression] (rather than function declarations [functions declarations, difference please refer to Chapter 2nd]) is not included in Vo[variable object.

A Variable object (Variable object) is an abstract concept that, in different contexts, represents the use of a different object. For example, in global context, a variable object is also the global object itself [Global object]. (This is where we can point to global variables through the properties of the global object).

Let's take a look at the global execution context in the following example:

Copy Code code as follows:

var foo = 10;

function bar () {}////Functions Declaration
(function Baz () {}); function expression

Console.log (
This.foo = = Foo,//True
Window.bar = = Bar/True
);

Console.log (BAZ); Reference error, Baz not defined

Variable objects (VO) in the global context can have the following properties:

Figure 7. Global variable Object

As shown above, the function "Baz" is not to be included in the variable object if it is an expression of a function. This is the reason for trying to access outside the function to generate a reference error (REFERENCEERROR). Note that there are only functions that can create new scopes, compared to other languages (for example, C + +) ECMAScript. Variables and internal functions defined within a function are not directly visible externally and do not pollute the global object. When using eval, we also use a new (eval-created) execution context. Eval uses the global variable object or the caller's variable object (the calling source of the Eval).

What about the function and its own variable object? In a function context, the variable object is represented as the active object (activation).
Active object (Activation object)
When the function is activated by the caller, this particular active object (activation object) is created. It contains generic parameters (formal parameters) and special parameters (arguments) objects (parameter mapping tables with indexed properties). The active object is used as a variable object in the function context.

That is, the variable object of the function remains unchanged, but the addition of the storage variable to the function declaration also contains the arguments of the special object.

Consider the following:

Copy Code code as follows:

function foo (x, y) {
var z = 30;
function bar () {}//Functions Declaration
(function Baz () {}); function expression
}
Foo (10, 20);

The next active object (AO) of the "Foo" function context is shown in the following illustration:

Figure 8. Activate Object

By the same token, function expression is not in AO's ranks.

The details of this AO can be found in chapter 9th of this series of tutorials.

What we're going to talk about is the third main object. It is well known that in ECMAScript we use internal functions [inner functions], in which we may refer to its parent function variable, or global variable. We make these variable objects the context scoped object [Scope object ']. Similar to the prototype chain discussed above [prototype chain], we call this the scope chain [scope chain].
scope Chains
A scope chain is a list of objects this are searched for identifiers appear in The code of the context. The
scope chain is a list of objects (list of objects) that retrieves the identifiers (identifiers) that appear in the context code. The principle of the
Copy code
Scope chain is similar to the prototype chain, and if the variable is not in its own scope, it looks for the parent until the topmost level. The

designator [Identifiers] can be understood as a variable name, a function declaration, and a generic argument. For example, when a function needs to refer to a variable within its own function, but the variable is not declared within the function (or not a parameter name), then the variable can be called a free variable [variable]. Then we need to use the scope chain to search for these free variables.

In general, a scope chain includes the parent variable object (variable object) (top of the scope chain), the function's own variable VO, and the active object (Activation objects). In some cases, however, other objects, such as the with or catch statements, are dynamically added to the scope chain during execution. [with-objects refers to the WITH statement, the resulting temporary scope object; catch-clauses refers to a catch clause, such as catch (e), which produces an exception object that results in a scope change].

When looking for an identifier, the lookup is started from the active object part of the scope chain, and then, if the identifier is not found in the active object, the top of the scope chain is searched for, as in the scope chain.

Copy Code code as follows:

var x = 10;

(function foo () {
var y = 20;
(function bar () {
var z = 30;
"X" and "Y" are free variables.
will be found in the next object in the scope chain (after the interaction object of the function "bar")
Console.log (x + y + z);
})();
})();

We assume that the object linkage of the scope chain is through a property called __parent__, which is the next object that points to the scope chain. This can be tested in the Rhino code, which is actually implemented in the ES5 environment (there is a link called outer). Of course, you can use a simple data to simulate this model. Using the concept of __parent__, we can show the above code as follows. (therefore, the parent variable is in the [[Scope]] property of the function.)

Figure 9. Scope chain

During code execution, the scope chain is changed if you use a with or catch statement. And these objects are simple objects, they also have a prototype chain. In this case, the scope chain is searched from two dimensions.

    1. First, in the original scope chain
    2. The chain of the scopes of each chain contact (if the link is prototype)

Let's look at the following example:

Copy Code code as follows:

object.prototype.x = 10;

var w = 20;
var y = 30;

In the SpiderMonkey global object
For example, the variable object for the global context is inherited from "Object.prototype"
So we can get "no declared global variables."
Because it can be retrieved from the prototype chain

Console.log (x); 10

(function foo () {

"Foo" is a local variable
var w = 40;
var x = 100;

"X" can be obtained from "Object.prototype", note that the value is 10 OH
Because {z:50} is inherited from it

With ({z:50}) {
Console.log (w, x, Y, z); 40, 10, 30, 50.
}

After the "with" object is removed from the scope chain
X is also available from the context of Foo, and note that this value is back to 100.
"W" is also a local variable
Console.log (x, W); 100, 40

In the browser
We can use the following statement to get the global W value
Console.log (WINDOW.W); 20

})();

We will have the following structure diagram. This means that before we go to search for __parent__, we will go to the __proto__ link first.

Figure 10. With the increased scope chain

Note that not all global objects are inherited by Object.prototype. The above diagram can be tested in SpiderMonkey.

As long as the variable objects of all external functions exist, there is nothing special about referencing external data from intrinsic functions--we just need to traverse the scope list and find the desired variable. However, as mentioned above, when a context terminates, its state and itself will be destroyed (destroyed), and the internal function will be returned from the external function. In addition, this returned function may be activated in other contexts, so what happens if a previously terminated context with some free variables is activated? Generally speaking, the concept of solving this problem is directly related to the scope chain in ECMAScript, known as the (lexical) closure ( Lexical) closure).
Closure (Closures)
In ECMAScript, a function is the "First Class" object. This term means that a function can be passed as a parameter to other functions (in which case the function is called "Funargs"-the abbreviation for "functional Arguments" [translated as appropriate for functional parameters]). Functions that receive "Funargs" are called higher-order functions (Higher-order functions) or, more closely, mathematical concepts, are referred to as operators (operators). Functions are also returned by the runtime of other functions, which are called function valued functions (functions with functional value).

There are two conceptual problems with "Funargs" and "functional Values", which are called "Funarg problem" ("Functional Parameter Problems"). To solve the problem of functional parameters accurately, we need to introduce the concept of closure (closures). Let's look at both of these issues (we can see that the [[Scope] property of the function is used in ECMAScript to solve the problem).

"Funarg problem" is a problem of "upward funarg problem" [may be translated as: the question of function parameters to look up]. This problem will occur when a function is returned from another function to the outside. To be able to enter a variable in the external context at the end of the external context, the intrinsic function is created (at creation moment) to be stored in the scope of the parent element of the [[Scope]] property. Then when the function is activated, the scope chain of the context is represented by the combination of the active object and the [[Scope]] property (in fact, as you can see in the figure above):

Scope chain = activation Object + [[Scope]]
Scope chain = active Object + [[Scope]]

Note that the main thing is that a function saves an external scope when it is created because the saved scope chain (saved scope chain) will be used in future function calls for variable lookup.

Copy Code code as follows:

function foo () {
var x = 10;
return function bar () {
Console.log (x);
};
}

"foo" returns a function as well.
And this returned function is free to use the internal variable x

var returnedfunction = foo ();

global variable "x"
var x = 20;

Support returned function
Returnedfunction (); The result is 10, not 20.

This form of scope is called static scope [static/lexical scope]. The x variable above is searched for in the [[Scope]] of the function bar. In theory, there will also be dynamic scopes, which means that the above x is interpreted as 20, not 10. However, Emcascript does not use dynamic scopes.

Another type of "Funarg problem" is the Top-down ["downward funarg problem"]. In this case, the parent is up and down, but there is ambiguity when judging a variable's value. That is, which scope the variable should use. Is it the scope of the function when it was created, or the scope at which it was executed? To avoid this ambiguity, closures can be used, that is, the use of static scopes.

Take a look at the following example:


Copy Code code as follows:

global variable "x"
var x = 10;

global function
function foo () {
Console.log (x);
}

(function (Funarg) {

Local variable "x"
var x = 20;

There's no ambiguity.
Because we use the global variable "x" saved in [[Scope]] of the "foo" function,
is not an "x" of the caller scope

Funarg (); 10, not 20.

}) (foo); Pass Foo as a "Funarg"

From the above, we seem to be able to conclude that in the language, the use of static scopes is a mandatory requirement for closures. However, in some languages, a combination of dynamic and static scopes is provided that allows the developer to choose which scope. In ECMAScript, however, only static scopes are used. Therefore, ECMAScript fully supports the use of properties of [[Scope]]. We can give the closure the following definition:

A closure is a combination of the a code block (in ECMAScript it is a function) and statically/lexically saved all parent SC Opes.
Thus, via these saved scopes a function could easily refer free variables.
Closures are a series of code blocks (functions in ECMAScript) and statically hold all the scopes of the parent. The saved scopes are used to search for the free variable in the function.
Copy Code
Note that because each normal function is saved [[Scope]] when it is created, in theory, all functions in ECMAScript are closures.

There is also an important point where several functions may contain the same parent scope (this is a common case, for example, with several internal or global functions). In this case, the variables that exist in [[Scope]] are shared. The variation of a variable in a closure can also affect another closure.
Copy Code code as follows:

function Baz () {
var x = 1;
return {
Foo:function foo () {return ++x;},
Bar:function Bar () {return--x;}
};
}

var closures = Baz ();

Console.log (
Closures.foo (),//2
Closures.bar ()//1
);

The above code can be represented by this graph:

Figure 11. shared [[Scope]]

When you create multiple functions in a loop, the diagram above raises a puzzle. If you use a loop variable (such as "K") in a function you create, all functions use the same loop variable, causing some programmers to often get no expected value. Now it's clear why this is so problematic-because all functions share the same [[Scope]], where the loop variable is the last duplicate assignment.

Copy Code code as follows:

var data = [];

for (var k = 0; k < 3; k++) {
Data[k] = function () {
Alert (k);
};
}

Data[0] (); 3, but not 0
DATA[1] (); 3, but not 1
DATA[2] (); 3, but not 2

There are some techniques to solve such problems. One technique is to provide an extra object in the scope chain, such as adding a function:

Copy Code code as follows:

var data = [];

for (var k = 0; k < 3; k++) {
DATA[K] = (function (x) {
return function () {
alert (x);
};
}) (k); Pass K as a parameter
}

The results are correct.
Data[0] (); 0
DATA[1] (); 1
DATA[2] (); 2


The in-depth study and practice of closure theory can be found in the 16th chapter of this series of tutorials (Closures). If you want more information about the scope chain, refer to the 14th chapter of the scope chain (scope chain) in this series of tutorials.

The next section will discuss the concept of an execution context's last attribute--this pointer.

This pointer
A This value is a special object which are related with the execution context.
Therefore, it may are named as a context object (i.e. an object in which context the execution context is activated).
This is a special object that is relevant to the context of execution. Therefore, it can also be referred to as the context object [context objects] (the contexts in which the execution context is activated).
Copy Code
Any object can be the this value of the context. I would like to clarify once again some of the descriptions associated with the execution context in ECMAScript, especially the misunderstanding of this. Typically, this is incorrectly described as a property of a variable object. It has recently been found in this book (although the chapter that mentions this in the book is good). Please keep in mind:

A This value are a property of the execution context and but not a property of the variable object.
This is an attribute of the execution context, not the property of a Variable object
Copy Code
This feature is important because unlike variables, this is not a process similar to a search variable. When you use this in your code, the value of this is obtained directly from the execution context and not from the scope chain. The value of this is determined only when the context is entered.

By the way, unlike ECMAScript, Python has an argument for self that is similar to this, but can be changed during execution. In ECMAScript, it is not possible to assign a value to this, because, or the sentence, this is not a variable.

In the global context, the value of this refers to the global object, which means that this value is the variable itself.
Copy Code code as follows:

var x = 10;

Console.log (
X,//10
This.x,//10
window.x//10
);

In the functional context [function contexts], this may be a different value depending on the function call each time. This is provided by each caller, caller by invoking an expression [call expression] Generated (that is, how this function is invoked). For example, in the following example, Foo is a callee that is activated in the global context. The following example shows that different caller cause this difference.
Copy Code code as follows:

Alert in the "foo" function doesn't change.
But every time the call is activated, this is different.

function foo () {
alert (this);
}

Caller activates "foo" this callee,
and provide "This" to this callee

Foo (); Global objects
Foo.prototype.constructor (); Foo.prototype

var bar = {
Baz:foo
};

Bar.baz (); Bar

(Bar.baz) (); Also bar
(Bar.baz = Bar.baz) (); This is a global object
(Bar.baz, Bar.baz) (); is also a global object
(False | | bar.baz) (); is also a global object

var otherfoo = Bar.baz;
Otherfoo (); or a Global object

If you want to think deeply about how this value changes (and more importantly how) in each function call, you can read chapter 10th this tutorial series. The situation mentioned above will be discussed in detail here Zhangne.

Summary (conclusion)
Here we have completed a short overview. Although it may not seem so short, it takes a whole book to complete the presentation. We did not mention two important topics: functions (functions) (and differences between different types of functions, such as function declarations and function expressions) and ECMAScript evaluation strategies ( Evaluation strategy). These two topics can be consulted separately in the 15th chapter of the Tutorial series (functions) and the 19th Evaluation Strategy (evaluation strategy).

If you have any comments, questions or supplements, I would be very welcome to discuss them in the article comments.

I wish you all a successful study ECMAScript.

Related Article

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.