[[Scope], scopechain, and executioncontext in javascript!

Source: Internet
Author: User
For a summary of the scope of javascript, refer to the above articles and add your own understanding. Recently, I am not familiar with the javascript scope and running process, especially when using closures. It is similar to exploring on the internet,

 

For a summary of the scope of javascript, refer to the above articles and add your own understanding.

Recently, I am not familiar with the javascript scope and running process, especially when using closures.

I tried to find out what I was doing on the Internet, but I didn't think that most of the articles on the Internet were vague and mostly identical. I searched through multiple parties and read some books by myself.

Finally, I have a little understanding of javascript. Record it in case you forget it.

To thoroughly understand the scope of javascript, we need to understand some concepts.

1. runtime Context

In javascript, only functions can create independent scopes. Note that for loops cannot be created. Otherwise, your code may get unexpected results.

 

for (var k in {a: 1, b: 2}) {  alert(k);}alert(k);

Even if the loop ends, alert can return the value of k.

2. variable objects and activity objects (VO/AO)

A variable object (VO) is a special object related to the execution context. It stores the following content declared in the context:

Variable (var, variable Declaration );

Function declaration (FunctionDeclaration );
Function Parameters

Only the variables in the global context can be indirectly accessed through the VO attribute name (because in the global context, the global object itself is a variable object ), in other contexts, you cannot directly access the VO object because it is only an implementation of the internal mechanism. Usually, AO (activation object is used to save the variable ).

VO:

 

var a = 10; functiontest(x) {  var b = 20; }; test(30);

The corresponding variable object is:

// Global context variable object

 

VO (globalContext) = {a: 10, test:
 
  
}; // Test function context variable object VO (test functionContext) = {x: 30, B: 20 };
 
2.1 global context variable object (VO)

First, we need to give a clear definition to the global object:

A Global object is an object created before any execution context is entered;
This object only has one copy, and its attributes can be accessed anywhere in the program. The life cycle of the global object ends at the moment when the program exits.

The Math, String, Date, and parseInt attributes of the global object are initialized in the initial creation phase, you can also create additional objects as attributes (which can point to the global object itself ). For example, in DOM, the window attribute of the global object can reference the global object itself (Of course, not all implementations are like this ):

 

Global = {Math: <...>, String: <...>... window: global // reference itself };

Prefix is often ignored when accessing global object attributes, because global objects cannot be accessed directly by name. However, we can still access global objects through this in the global context. We can also reference ourselves recursively. For example, window in DOM. To sum up, the code can be abbreviated:

 

String (10); // global. string (10); // window with the prefix. a = 10; // = global. window. a = 10 = global. a = 10; this. B = 20; // global. B = 20; alert (this = window); here we can see that calling with winodow is actually an attribute in VO, and using this is a global variable. Therefore, return to the variable object in the global Context -- here, the variable object is the global object itself: VO (globalContext) = global; it is necessary to understand the above conclusion. Based on this principle, in the global context, we can access the global object indirectly through the attributes of the Global Object (for example, we do not know the variable name beforehand ). Var a = new String ('test'); alert (a); // for direct access, find testalert (window ['a']) in VO (globalContext); // access via global indirectly: global === VO (globalContext): testalert (a === this. a); // truevar aKey = 'a'; alert (window [aKey]); // access by dynamic attribute name indirectly: test
2.2 variable object in the function context (AO)

In the context of function execution, VO cannot be directly accessed. At this time, the active object (AO) plays the role of VO.

VO (functionContext) = AO;

An active object is created when the context of the function is entered. It is initialized through the arguments attribute of the function. The value of the arguments attribute is an Arguments object:

 

AO = {  arguments: };

An Arguments object is an attribute of an activity object. It includes the following attributes:

Callee-reference to the current function

Length-Number of actually passed parameters

The properties-indexes (an integer of the string type) attribute value is the parameter value of the function (arranged from left to right by the parameter list ). The number of elements in properties-indexes is equal to that in arguments. length. properties-indexes and the actually passed parameters are shared.

For example:

 

Function foo (x, y, z) {// number of declared function parameters arguments (x, y, z) alert (foo. length); // 3 // The number of actually passed parameters (only x, y) alert (arguments. length); // 2 // The callee parameter is the alert (arguments. callee = foo); // true // The parameter shares alert (x = arguments [0]); // true alert (x ); // 10 arguments [0] = 20; alert (x); // 20 x = 30; alert (arguments [0]); // 30 // However, the Parameter z that is not passed in is not shared with the 3rd index values of the parameter z = 40; alert (arguments [2]); // undefined arguments [2] = 50; alert (z); // 40} foo (10, 20 );

The code in this example has a bug in the current Google Chrome browser-even if the z, z, and arguments [2] parameters are not passed, they are still shared.

3. Scope chain

As you can see above, each context has its own variable object: for a global context, it is the global object itself; for a function, it is the activity object.

 

var x = 10;function foo() {var y = 20;  function bar(){alert(x +y);}return bar;}foo()(); // 30

The scope chain is the list of all variable objects (including parent variable objects) in the internal context. This link is used for variable query. In the preceding example, the scope chains of bar context include AO (bar), AO (foo), and VO (global ). Both AO (foo) and VO (global) come from the parent variable object.

 

The scope chain is related to an execution context. The variable object chain is used for Variable Search in identifier parsing.

 

The scope chain of the function context is created when a function is called, including the activity object and the [[scope] attribute inside the function.

 

The following figure shows the context: activeExecutionContext = {VO :{...}, // or AO context initialize VO/AOthis: thisValue, Scope: [// Scope chain, Scope chain // list of all variable objects // for identifiers lookup]};

Its scope is defined as follows:

Scope = AO + [[Scope]

This association and identifier parsing process will be discussed below, which is related to the function lifecycle.

For Scope = AO + [[Scope], when a function is called, the context will create a Scope China, that is, the Scope attribute, and then initialize it as the internal attribute of the function, that is, the function internal attribute [[Scope], and then the VO/AO created when the context is entered, Which is pushed to the frontend of Scopechina.

3.1 create a function

The [[scope] attribute of a function is the hierarchical chain of all parent variable objects. It is located above the current function context. When a function is created (the function life cycle is divided into the function creation and function call stages) stored in it. A function can access variable objects in a higher context. This mechanism is implemented by the [[scope] attribute inside the function.

Note: [[scope] is stored when a function is created. It is static (unchanged) and always ends until the function is destroyed. That is, the function can never be called, but the [[scope] attribute has been written and stored in the function object. Because it is static storage, the [[scope] attribute of the internal function is the hierarchical chain of all parent variables, which leads to the existence of the closure. As follows:

 

Var x = 10; function foo () {alert (x) ;}( function () {var x = 20; foo (); // 10, but not 20, access x} () in VO of [[scope] in foo })();

This example also clearly shows that [[scope] of a function (in this example, it is an anonymous function returned from the function "foo") persists, even after the scope of the function is created.

Another thing to consider is that [[scope] is an attribute of a function rather than context in contrast to the scope chain. Considering the above example, the [[scope] of the function "foo" is as follows:

 
foo.[[Scope]] = [ globalContext.VO // === Global ];

For example, we use the common ECMAScript array to display the scope and [scope].

3.2 Function Activation

As mentioned in the definition, after creating AO/VO In the context, the Scope attribute of the context (a Scope chain of Variable Search) is defined as follows:

Scope = AO | VO + [[Scope]

The code above indicates that the active object is the first object in the scope array, that is, the frontend added to the scope.

Scope = [AO]. concat ([Scope]);

This feature is very important for the processing of identifier parsing.

Identifier Parsing is a processing process used to determine which variable object a variable (or function declaration) belongs.

In the return value of this algorithm, we always have a reference type. Its base component is the corresponding variable object (or null if not found ), the property name component is the name of the identifier to be searched up.

The identifier parsing process contains the search for the attribute corresponding to the variable name, that is, the continuous search of the variable object in the scope, starting from the deepest context, bypassing the scope chain until the top.

In this way, the local variables in a context have a higher priority than the variables in the parent scope. If two variables have the same name but come from different scopes, the first one is found in the deepest scope.

We use a slightly complex example to describe the above.

 

var x = 10;functionfoo() {var y = 20;function bar() {var z = 30;alert(x +  y +z);  }  bar();}foo(); //60

 

In this regard, we have the following variables/activity objects, the [[scope] attributes of functions, and the scope chain of context:

The global context variable object is:

 

globalContext.VO=== Global = {  x: 10  foo: 
 
  };
 

 

When "foo" is created, the [[scope] attribute of "foo" is:

foo.[[Scope]]= [  globalContext.VO];

When "foo" is activated (entering the context), the activity object of the "foo" context is:

 

fooContext.AO= {  y: 20,  bar: 
 
  };
 

The scope chain of the "foo" context is:

 

fooContext.Scope= fooContext.AO + foo.[[Scope]] // i.e.: fooContext.Scope= [  fooContext.AO,  globalContext.VO];

When the internal function bar is created, its [[scope] is:

 

bar.[[Scope]]= [  fooContext.AO,  globalContext.VO];

 

When bar is activated, the activity object in the bar context is:

 

barContext.AO= {  z: 30};

The scope chain of the bar context is:

 

barContext.Scope= barContext.AO + bar.[[Scope]] // i.e.: barContext.Scope= [  barContext.AO,  fooContext.AO,  globalContext.VO];

The identifiers of "x", "y", and "z" are parsed as follows:

 

-x--barContext.AO // not found--fooContext.AO // not found--globalContext.VO // found - 10 -y--barContext.AO // not found--fooContext.AO // found - 20 -z--barContext.AO // found – 30
4 Closure

 

A common way to create a closure is to create another function within a function. Take the create () function as an example:

 

function create(){var x = 0return function(){       alert(++x);};}var c = create();c();     //alert 1not 0c();     //alert 2not 0c();     //alert 3not 0 

The internal function (an anonymous function) in the code above accesses the variable x in the external function. Even if this internal function is returned and called elsewhere, it can still access variable x. the reason why the variable can be accessed is that the scope chain of the internal function contains the scope of create.

When a function is called for the first time, an execution environment and corresponding Scope chain are created, and a special internal attribute ([Scope]) is assigned to the Scope chain. Then, use the value of this, arguments, and other named parameters to initialize the function's activity object. Then, the activity object is pushed to the frontend of the scope chain. Therefore, in the scope chain, the parent activity object is always in the second place until the global execution environment at the end of the scope chain.

During function execution, to read and write the value of a variable, you need to find the variable in the scope:

 

 function compare(value1,value2){     if(value2
 
  value2){          return1;    }     else {        return0;    }   }   var result =compare(5,10);
 

The above code first defines the compare () function and calls it in the global scope. When compare () is called for the first time, an activity object containing this, arguments, value1, and value2 is created. The variables (including this, result, and compare) in the global execution environment are second in the scope of the compare () execution environment,

Each execution environment in the background has an object that represents a variable-a variable object. Variable objects in the global environment always exist, while variable objects in local environments such as the compare () function only exist during function execution.When creating the compare () function (Note: This is the creation), a scope chain containing the global variable object is created, this Scope chain is stored in the internal [Scope] attribute. When the compare function is called, an execution environment is created for the function, and the Scope chain of the execution environment is constructed by copying objects in the [[Scope] attribute of the function.

Then, an activity object (used as a variable object here) is created and pushed to the front end of the execution environment scope chain. In this example, the execution environment of the compare () function contains two variable objects: local activity objects and global variable objects.

The scope chain is essentially a pointer list pointing to a variable object. It only references but does not actually include a variable object.

Generally, after the function is executed, the partial activity object is destroyed, and only the global scope is saved in it, but the closure condition is different. The function defined in another function adds the activity objects containing the function to its scope chain. Therefore, the scope chain of the anonymous function defined in the createComparisonFunction () function actually contains the activity object of the external function createComparisonFunction,

 

function createComparisonFunction(propertyName){   return function(object1,object2){        varvalue1 = object1[propertyName];        varvalue1 = object2[propertyName];        if(value1 < value2){return -1;}        elseif (value1>value2){return 1;}        else{return 0;}   };}

 

var compare =createComparisonFunction(name);var result =compare({name:'Nicholas},{name:Greg});

In the anonymous function from createComparisonFunction(), Its scope chain is initialized to include createComparisonFunction() The activity object and global variable object of the function. In this way, createComparisonFunction() After the function is executed, its activity object will not be destroyed, because the scope chain of the anonymous function is still referencing this activity object. In other words, createComparisonFunction() After a function is returned, the scope chain of its execution environment will be destroyed, but its activity object will remain in the memory. After the anonymous function is destroyed, createComparisonFunction() Will be destroyed.

5 Closures and variables

See the following code:

 

function fn(){    var result =new Array();    for (vari=0;i<10;i++){      result[i]= function(){return i;}   }    returnresult;}var funcs = fn();for (var i=0;i
 
  );}
 

This code may be classic. You may know that 10 10 results will be output.

The reason for this is the scope issue.

After fn is called, The I value saved in the AO of fn's function chain is 10.

The main problem is that the parent activity object is saved in the Action chain of result [I. Then, when the result method is activated, it will first search for its own activity object. If no indicator is found, it will search for it in the parent activity object. When I is found, this I is already 10. This is why all results are 10. If you need to get the expected results, you can use the following method:

 

 

result[i] = function(num){     returnfunction(){        returnnum;    }}(i);

Why can we get the correct results? In fact, this is the activity object that will modify the result.

The first result function has an additional num attribute in the activity object, which is passed in using an auto-start function. When you activate a function, you can directly search for num in your own activity object and then return the result. Instead of searching for the parent variable. In this way, the problem is solved.

6. javascript code execution process

Some functions in javascript are not mentioned here.

[[Scope] of a function object is an internal attribute.

The Functiion object automatically creates an [[scope] internal attribute when it is created, and only the js engine can access it. A scope chian chain will also be created. [Scope] is linked to scope china.

 

 

function add(){  Var name = “hello”;}

As shown above:

Function add creates a [[scope] attribute when it is created and points to scope chian. because it is in a global environment, scope chian just points to window action object. (It is not clear here ).

In this case, the above conditions must be defined, and can be said to be completed during js interpretation.

 

When this function is executed, an internal object called "execution context" is created, and the runtime context defines the environment when the function is executed. Each runtime context has its own scope chain for identifier parsing. When the runtime context is created, its Scope chain is initialized to the objects contained in the [[Scope] of the currently running function.

 

The context code in the runtime is divided into two basic stages for processing:

Enter execution Context

Execute Code

Changes to variable objects are closely related to these two phases.

Note: The processing of these two phases is a general action and is irrelevant to the context type (that is, the global context and function context are the same ).

6.1 enter the execution Context

When you enter the execution context (before code execution), VO/AO contains the following attributes (as mentioned earlier ):

All parameters of the function (if we are in the context of function execution)

-The property of a variable object consisting of a name and a corresponding value is created. If no corresponding parameter is passed, the attributes of a variable object consisting of the name and undefined value will also be created.

All function declarations (FunctionDeclaration, FD)

-The property of a variable object consisting of a name and a corresponding value (function object) is created. If the variable object already has an attribute with the same name, the property is completely replaced.

All variable declarations (var, VariableDeclaration)

-Attributes of a variable object composed of the name and the corresponding value (undefined) are created. If the variable name is the same as the declared parameters or functions, the variable declaration does not interfere with the existing attributes.

Let's take an example:

 

function test(a, b) {  var c = 10;  function d(){}  var e =function _e() {};  (function x(){});}test(10); // call

 

When entering the context of the test function with the parameter 10, AO performs as follows:

 

AO(test) = {  a: 10,  b: undefined,  c: undefined,  d:
 
    e: undefined};
 

Note that AO does not contain the function "x ". This is because "x" is a function expression (FunctionExpression, abbreviated as FE) rather than a function declaration. function expressions do not affect VO. In any case, the function "_ e" is also a function expression, but as we will see below, because it is assigned to the variable "e ", therefore, it can be accessed by the name "e.

After that, the second stage of processing the context code is executed.

 

6.2 Code Execution

In this period, AO/VO already has attributes (however, not all attributes have values, and most attribute values are still the default undefined values ).

In the previous example, AO/VO was modified as follows during code interpretation:

 

AO['c'] = 10;AO['e'] = 
 
  ;
 

 

Note that since FunctionExpression "_ e" is saved to the declared variable "e", it still exists in the memory. FunctionExpression "x" does not exist in AO/VO. That is to say, if we want to call the "x" function, no matter before or after the function is defined, an error "x is not defined" will occur. unsaved function expressions can be called only in their own definitions or recursion.

 

Another typical example:

 

alert(x); // functionvar x = 10;alert(x); // 10x = 20;function x() {};alert(x); // 20

Why does the first alert "x" return a function, and it still accesses "x" before "x" is declared? Why not 10 or 20? Because, according to the canonicalized function declaration is filled in when the context is entered; the consent period, when the context is entered, there is a variable Declaration "x", as we said in the previous stage, variable declaration follows the function declaration and formal parameter declaration in sequence, and enters the context stage, the variable declaration does not interfere with the existing function declaration of the same name or formal parameter declaration in VO. Therefore, when entering the context, the VO structure is as follows:

 

VO = {}; VO ['X'] =
 
  
// Find var x = 10; // If functionx has not been declared, // at this time, the value of x should be undefined // but the variable declaration in this case does not affect the value of function with the same name VO ['X'] =
  
   
Then, in the code execution stage, VO makes the following changes: VO ['X'] = 10; VO ['X'] = 20;
  
 

We can see this effect in the second and third alert.

In the following example, we can see that the variables are put into VO at the context stage. (Because, although some else code will never be executed, the variable "B" still exists in VO .)

 

If (true) {var a = 1;} else {var B = 2;} alert (a); // alert (B); // undefined, not declared by B, the value of B is undefined.

 

7. Variables

Generally, various articles and JavaScript-related books claim that "a variable can be declared whether the var keyword is used (in the Global Context) or the var keyword is not used (anywhere ". Remember, this is an incorrect concept:

Variables can only be declared by using the var keyword at any time.

The above assignment statement:

A = 10;

This only creates a new attribute for the Global Object (but it is not a variable ). "Not a variable" does not mean that it cannot be changed, but does not comply with the variable concept in the ECMAScript specification, so it is "not a variable" (the reason why it can become a global object attribute, this is because VO (globalContext) = global. Do you still remember this ?).

Let's take a look at the specific differences through the following examples:

 

Alert (a); // undefinedalert (B); // B does not declare B = 10; var a = 20;

 

The root cause is still VO and enters the context and code execution phases:

Enter the context stage:

 

VO = {a: undefined};

 

We can see that "B" is not a variable, so there is no "B" at this stage ", "B" will only appear in the code execution phase (but in our example, an error has occurred before it reaches ).

Let's change the example code:

 

Alert (a); // undefined, as we all know, B = 10; alert (B); // 10. Create var a = 20 in the code execution phase;

 

There is also an important knowledge point about variables. Compared with a simple attribute, a variable has a feature (attribute): {DontDelete}. This feature means that the delete operator cannot be used to directly delete the variable attribute.

 

A = 10; alert (window. a); // 10 alert (delete a); // truealert (window. a); // undefinedvar B = 20; alert (window. b); // 20 alert (delete B); // falsealert (window. b); // still 20. However, this rule cannot be omitted in a context, that is, the eval context. The variable does not have the {DontDelete} feature. Eval ('var a = 10; '); alert (window. a); // 10 alert (delete a); // truealert (window. a); // undefined

 

When you use a debugging tool (for example, Firebug) to test the instance, you must note that Firebug also uses eval to execute your code on the console. Therefore, the variable property does not have the {DontDelete} feature and can be deleted.

 

If you can read the blog carefully, I believe you will be very interested in javascript.

If the document is helpful to you, congratulations.

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.