Suitable readers: experienced developers, professional front-end personnel.
Original author: Dmitry A. Soshnikov
Release time: 2010-09-02
Original text: 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
Main It combines the Chinese translations of the two experts above and combines the best parts of the two articles together.
Let’s first take a look at the concept of object [Object], which is also the most basic concept in ECMASript.
Object Object
ECMAScript is a highly abstract object-oriented language, used to deal with Objects objects. Of course, there are also basic types, but when necessary, they also need to be converted into object objects. use.
An object is a collection of properties and has a single prototype object. The prototype may be either an object or the null value. The prototype object [prototype object]. This prototype object [prototype object] can be an object or null value.
Copy code
Let us take an example of a basic Object. First, we must understand that the prototype of an Object is a reference to the internal [[prototype]] attribute.
But generally speaking, we will use __
Figure 1. A basic object with a prototype
Why do we need prototypes? Let us consider the concept of prototype chain to answer this question.
Prototype chain
Prototype objects are also ordinary objects, and may also have their own prototypes. If the prototype of a prototype object is not null, we call it a prototype. Chain (prototype chain).
A prototype chain is a finite chain of objects which is used to implemented inheritance and shared properties.
Imagine a situation like this, 2 objects, most of the content is the same, only a small part is different. Obviously, in a good design pattern, we will need to reuse that part of the same, and Do not define the same methods or properties repeatedly in every object. In a class-based system, these reused parts are called inheritance of classes - the same parts are put into class A, then class B and class C inherit from A and can claim something unique of each.
ECMAScript has no concept of classes. However, the concept of reuse is no different (in some respects, even more flexible than class-) and can be implemented by the prototype chain. This kind of inheritance is called delegation based inheritance, or more popularly, prototypal inheritance.
Similar to classes "A", "B", "C", in ECMAScript you create object classes "a", "b", "c", accordingly, object "a" owns object " The common part of b" and "c". At the same time objects "b" and "c" only contain their own additional properties or methods.
Figure 2. Prototype chain
Prototype chains are usually used in situations where objects have the same or similar state structure (i.e. the same set of properties) and different state values. In this case, we can use Constructor to create objects in a specified pattern.
Constructor
In addition to creating objects, the constructor also does another useful thing - automatically sets the prototype object for the new object created. . The prototype object is stored in the ConstructorFunction.prototype property.
For example, if we rewrite the previous example and use the constructor to create objects "b" and "c", then object "a" plays the role of "Foo.prototype":
Figure 3. The relationship between constructors and objects
As can be seen from the above diagram, each object has a prototype. The constructor Foo also has its own __proto__, which is Function.prototype, and the __proto__ of Function.prototype points to Object.prototype. Let me reiterate , Foo.prototype is just an explicit attribute, that is, the __proto__ attribute of b and c.
A complete and detailed explanation of this issue can be found in Chapters 18 and 19 that Uncle will soon translate. There are two parts: Object-oriented programming. The general theory (OOP. The general theory), which describes different object-oriented paradigms and stylistics (OOP paradigms and stylistics), and comparison with ECMAScript. Object-oriented programming. ECMAScript implementation (OOP) . ECMAScript implementation), which specifically talks about object-oriented programming in ECMAScript.
Now that we have understood the basic object principles, let’s take a look at the program execution environment [runtime program execution] in ECMAScript. This is commonly called the "execution context stack" [execution context] stack]. Each element can be understood abstractly as an object. You may have discovered that, yes, in ECMAScript, you can see objects almost everywhere.
Execution Context Stack
There are three types of code in ECMASscript: global, function and eval.
The execution of each type of code depends on its own context. Of course, the global context may cover many function and eval instances. Every time a function is called, it will enter the context of function execution and calculate the values of variables in the function. Each execution of the eval function will also enter the context of the eval execution to determine where the value of the variable should be obtained.
Note that a function may generate unlimited contexts, because a function call (even recursion) generates a new context.
Figure 4. Execution context stack
When a program starts, it will first enter the global execution context [global execution context], which is also the bottom element in the stack. This global program will start to initialize and generate necessary objects and functions. During the execution of this global context, it may activate some methods (already initialized of course) and then enter their context. environment and then push the new element onto the stack. After these initializations are completed, the system will wait for some events (such as user mouse clicks, etc.), trigger some methods, and then enter a new context.
See Figure 5. There is a function context "EC1" and a global context "Global EC". The following figure shows the changes in the stack when entering and exiting "EC1" from "Global EC":
Figure 5. Changes in execution context stack
This is how the ECMAScript runtime system manages code execution.
For information about the ECMAScript execution context stack, please refer to Chapter 11 Execution context (Execution context) 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 required to execute its code.
Execution Context
An execution context can be understood abstractly as an object. Each execution context has a set of properties (called context states) that are used to track the execution progress of the associated code. This diagram is the structure of a context.
Figure 6. Context structure
In addition to these three required attributes (variable object (variable object), this pointer (this value), scope chain (scope chain)), the execution context depends on the specific Implementations can also have any additional properties. Next, let's take a closer look at these three properties.
Variable Object
A variable object is a scope of 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 within the context.
A variable object is the scope of data related to the execution context.
It is a special object associated with the context and is used to store variables and function declarations defined in the context.
Copy code
Note: Function expressions [function expressions] (rather than function declarations [function declarations, please refer to Chapter 2 of this series for the difference]) are not included in VO[variable object].
Variable Object is an abstract concept. In different contexts, it represents the use of different objects. For example, in the global context, the variable object is also the global object itself. (This is why 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:
Figure 7. Global variable object
As shown above, the function "baz" is not included in the variable object if it is used as a function expression. This is why trying to access outside a function produces a ReferenceError. Please note that in ECMAScript, compared to other languages (such as C/C++), only functions can create new scopes. Variables and internal functions defined inside the function are not directly visible outside and do not pollute the global object. When using eval, we will also use a new (eval-created) execution context. eval will use the global variable object or the caller's variable object (the source of eval's call).
What about functions and their own variable objects? In the context of a function, variable objects are represented as activation objects.
Activation object
When a function is activated by the caller, this special activation object is created. It contains normal parameters (formal parameters) and special parameter (arguments) objects (parameter mapping table with indexed attributes). Active objects are used in function context as variable objects.
That is: the variable object of the function remains unchanged, but in addition to the storage variables and function declarations, it also contains special object arguments.
Consider the following situation:
Figure 8. Activating objects
For the same reason, function expression is not included in AO.
Details of this AO can be found in Chapter 9 of this series of tutorials.
What we are going to talk about next is the third main object. As we all know, in ECMAScript, we will use inner functions [inner functions]. In these inner functions, we may refer to its parent function variables or global variables. We call these variable objects the scope object of the context. Similar to the prototype chain discussed above, we call it the scope chain here.
Scope Chains
A scope chain is a list of objects that are searched for identifiers appear in the code of the context.
A scope chain is a list of objects (list of objects) to retrieve identifiers that appear in the context code.
Copy code
The principle of scope chain is very similar to prototype chain. If the variable does not exist in its own scope, then it will look for the parent, all the way to the top level.
Identifiers [Identifiers] can be understood as variable names, function declarations and ordinary parameters. For example, when a function needs to reference a variable within its own function body, but the variable is not declared inside the function (or is not a parameter name), then the variable can be called a free variable [free 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 (the top of the scope chain), the function's own variable VO and the activation object. However, in some cases other objects may also be included, such as dynamically added to the scope chain during execution - such as with or catch statements. [Annotation: with-objects refers to the temporary scope object generated by the with statement; catch-clauses refers to the catch clause, such as catch(e), which will generate exception objects and cause scope changes].
When looking for an identifier, it starts at the active object part of the scope chain, then (if the identifier is not found in the active object) searches at the top of the scope chain, and so on, just like the action Like a domain chain.
Figure 9. Scope chain
During code execution, using the with or catch statement will change the scope chain. These objects are simple objects, and they will also have prototype chains. In this case, the scope chain will be searched in two dimensions.
Let’s look at the following example:
Figure 10. withincreased scope chain
Note that not all global objects are inherited from Object.prototype. The situation illustrated above 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 internal functions - we just traverse the scope list and find the required variables. However, as mentioned above, when a context terminates, its state and itself will be destroyed, and the inner function will return from the outer function. Furthermore, the returned function may later be activated in other contexts, so what happens if a previously terminated context with some free variables is activated again? Generally speaking, the concept of solving this problem is similar to that in ECMAScript. Scope chains are directly related and are called (lexical) closures.
Closures
In ECMAScript, functions are "first-class" objects. This term means that functions can be passed as arguments to other functions (in this case, the function is called "funargs" - short for "functional arguments" [Annotation: I don't know if it is translated as functional arguments appropriately]) . Functions that accept "funargs" are called higher-order functions, or, more mathematically, operators. The runtime of other functions will also return functions, and these returned functions are called function valued functions (functions with functional value).
There are two conceptual problems between "funargs" and "functional values". These two sub-problems are called the "Funarg problem" ("functional parameter problem"). To accurately solve the problem of functional parameters, the concept of closure needs to be introduced. Let us describe these two problems in detail (as we can see, the [[Scope]] attribute of functions is used in ECMAScript to solve this problem).
A sub-problem of the "funarg problem" is the "upward funarg problem" [Annotation: It may be translated as: the upward search function parameter problem]. This problem will arise when a function returns to the outside from other functions. To be able to access the variables of the external context when the external context ends, the internal function needs to store it in the scope of the parent element of the [[Scope]] attribute at the time of creation (at creation moment). Then when the function is activated, the context's scope chain appears as the activation object combined with the [[Scope]] attribute (in fact, you can see it in the picture above):
Scope chain = Activation object [[ Scope]]
Scope chain = active object [[Scope]]
Please note that the main thing is - the function saves the outer scope when it is created, because of this saved role The saved scope chain will be used for variable lookup in future function calls.
Figure 11. Shared [[Scope]]
The above picture can cause confusion when creating multiple functions in a loop. If you use a loop variable (such as "k") in the created function, then all functions use the same loop variable, causing some programmers to often not get the expected value. Now it is clear why such a problem occurs - because all functions share the same [[Scope]], where the loop variable is the last complex assignment.