1.1.1 Summary
As we learn JavaScript, we often encounter concepts such as scope (scope) and execution context (context). Where the execution context is closely related to the This keyword.
With object-oriented programming experience, you are familiar with this keyword, so it is easy to associate it with object-oriented programming, which points to objects that are newly created with the constructor, and in ECMAScript, this is supported. , however, as is well known, this is not just a representation of the objects created.
In the next blog post we'll talk about the scope and execution context of JavaScript, and how they differ.
Directory
- Scope
- Execution Environment
- Contextual issues
- Context instance Issues
- Cross-scope context
- Use the context to resolve a scope problem
- Using scopes to resolve context issues
1.1.2 Body
The execution Environment (execution context), also known as the "Environment", is one of the most important concepts in JavaScript. The execution environment defines the other data that a variable or function has access to, and determines their respective behavior. Each execution environment has a variable object associated with it, and all variables and functions defined in the environment are stored in the object.
See the definition of execution environment a little dizzy, in short, " each execution environment has a variable object associated with it "; here's a question of how this variable object is defined.
Next, let's look at the definition of a variable object, which is implemented as follows:
/** * Execution Context skeleton. */activeexecutioncontext = { //variable object. VO: {...}, this:thisvalue};
Through the pseudo code above we know the object literal Activeexecutioncontext, which contains a variable object VO and this property.
This shows that this is related to the executable code type of the context, whose value is determined during the context stage and cannot be changed during the execution of the Code (for this use you can read some learning summaries of Javascript this).
Scope (scope) controls the visibility and life cycle of variables and parameters.
In short, the execution environment is object-based, and the scope is function-based.
Scope
We will introduce the use of scopes using an example, first, we define a function Fooa () and Foob, the sample code is as follows:
/** * defines a function. */var Fooa = function () { var a = 1; var foob = function () { var b = 2; Console.log (A, b); Outputs:1, 2 } Console.log (A, B);//error! B is not DEFINED}FOOA ();
In the example, the second log output variable is undefined because the parameters and variables defined in the function in JavaScript are not visible outside the function, and the parameters and variables defined anywhere inside a function can be seen anywhere inside the function.
Execution Environment
First, we define the object literal O, which contains an attribute X and Method M (), with the sample code as follows:
/** * defines a literal object. * @type {Object} */var o = { x:23, m:function () { var x = 1; Console.log (x, this.x); Outputs 1, }}o.m ();
The two variables and attribute x in the example can be accessed, but they are accessed in a very different way, access to the first X in log is accessed by the local variable x by scope, and this.x is accessed by the execution context to the property X of the object o, so the output values are not the same.
Contextual issues
Next, let's modify the previous example by adding a function f () to the method M (), as shown in the following example code:
/** * defines a literal object. * @type {Object} */var o = { x:23, m:function () { var x = 1; var f = function () { console.log (x, this.x);//outputs 1, undefined } f ();} } O.M ();
Above, we output the value of X by calling Method M (), because the implementation of method M () is implemented by calling function f ().
When we call the object O's Method m (), we find that this.x is undefined.
What is the reason for this? Recall the previous example, because the method M () Gets the context of the object o, so this is pointing to the object o, is the function f () does not get the context of the object O, so it is not clear which object this point?
First let's review the differences between the functions and methods and the properties and variables: Methods and object associations, such as Object.mymethod = function () {}, and function non-object association: var myFunc = function {}; The same property is Object-relational, For example: Object.myproperty = 23, and variable: var myproperty = 23.
Because we mentioned that the context is object-based, the function f () cannot get the execution context of the object o.
Can we let the function f () Get the execution context of the object O? Let's think about it, since function f () is not clear about the object it is pointing to, then it is OK to call the properties of the object directly.
/** * Fixs Broken context issue. * @type {Object} */var o = { x:23, m:function () { var x = 1; var f = function () { console.log (x, o.x);//outputs 1,% } f ();} } O.M ();
We call the property X of the object o directly in function f () so that the function f () does not need to get the property of the execution context directly calling the object.
Now, we have a new problem, if the object is not O but P, then we need to modify the function f () in the object, the more serious situation is that we have no way to determine which object, the sample code is as follows:
/** * defines a literal object. * @constructor */var C = function () {}c.prototype = { x:23, m:function () { var x = 1; var f = function () { console.log (x, this.x);//outputs 1, undefined } f ();} } var Instance1 = new C (); instance1.m ();
Context instance Issues
Above, we define the function C and its prototype object, and we can create the C object instance Instance1 by new method, and solve the broken context problem in the previous way, the concrete implementation is as follows:
/** * defines a literal object. * @constructor */var C = function () {}c.prototype = { x:23, m:function () { var x = 1; var f = function () { console.log (x, instance1.x);//outputs 1, undefined } f ();} } var Instance1 = new C (); instance1.m ();
If we were to create a C object instance Instance2, we wouldn't be able to specify the object in function f ().
In fact , this is an abstraction of an object instance, and when instances have multiple or even hundreds, we need to refer to these object instances through this.
Therefore, the specified object method does not effectively resolve the broken context problem, and we still need to use this to refer to the object, as we mentioned earlier because the function f () does not get the execution context of the object o, so it is unclear which object this is pointing to , so the output this.x is undefined, so we can let the function f () Get the execution context of the object.
Cross-scope context
We think that since the method is object-based and can get the object's execution context, we define f () directly as a method.
Now, we define method F () in the C object prototype, the sample code is as follows:
/** * defines a literal object. * @constructor */var C = function () {}c.prototype = { x:10, m:function () { var x = 1; THIS.F (); }, f:function () { console.log (x, this.x);//Reference error!! }} var Instance1 = new C (); instance1.m ();
OK, we define method F () in the C object prototype, then method F () can get the object's execution context.
Now, we run the above code in Firefox, the result output reference ERROR, what is the reason? We thought about the problem. In the variable x, because method F () cannot get the scope of method M (), the variable x is not in method F ().
Use the context to resolve a scope problem
We're in a dilemma. Method F () takes both the execution context and the scope of the method M (), and if we want to get the scope of the method m (), then we need to define the method F () in M ().
Next, we define the method F () in M (), which is implemented as follows:
/** * defines a literal object. * @constructor */var C = function () {}c.prototype = { x:23, m:function () { var x = 1; THIS.F = function () { console.log (x, this.x);//outputs 1, + this.f ();} } var Instance1 = new C (); instance1.m ();
Now that we call method F () through this, it can now get the object Instance1 execution context, and can also get the scope of method m (), so method F () can get the value of the property and variable x.
Using scopes to resolve context issues
Next, continue to see an example, we want to call the method OnTimeOut () in the function settimeout (), which is defined as follows:
/** * setTimeout function with broken Context issue * @type {Object} */var o = { x:23, ontimeout:function () {
console.log ("x:", this.x); }, m:function () { setTimeout (function () { this.ontimeout (); ERROR:this.onTimeout is not a function }, 1);} } O.M ();
Similarly, calling Method OnTimeOut () in function settimeout () fails, we know that this is because the method OnTimeOut () cannot get the object execution context.
We know that the object execution context can be obtained in Method M (), so you can refer to the object that this is pointing to by a temporary variable, with the following instance code:
/** * Fixs setTimeout function with broken Context issue. * @type {Object} */var o = { x:23, ontimeout:function () { Console.log ("x:", this.x); Outputs , m:function () { //keeps instance reference. var = this; SetTimeout (function () { //Gets m scrope. Self.ontimeout (); }, 1);} } O.M ();
Above, we save the reference to this by the temporary variable self, because the settimeout () function can get the scope of M (), which we can pass by self. The OnTimeOut () method is called in OnTimeOut () mode.
1.1.3 Summary
This blog post describes the similarities and differences between execution contexts and scopes, the use of this and variable objects, and allows us to deepen our understanding of JavaScript language features.
First, we describe the relationship between the execution context and this, and the execution context is the object, and the scope is then introduced to make the variable visible in scope, and the scope is function-based.
We have introduced specific examples of the effects of this and the variables in different scopes and execution contexts , deepening the understanding of scope and execution context, thus helping us to better read and write code.
Some study summaries of javascript--context and scope