In-depth parsing of the use of the this keyword in JavaScript programming, javascriptthis
What exactly does this in JavaScript mean? Many people will tell you that this refers to the current object. Is that true? In most cases, it is true. For example, we often write such JavaScript on the webpage:
<Input type = "submit" value = "submit" onclick = "this. value = 'submitting data'"/>
Here this clearly refers to the current object, that is, the submit button. Generally, we use this in a similar way. But what is not the case?
Let's take a look at this example:
var foo = function() { console.log(this);}foo();new foo();
Comparing the running results of foo () and new foo (), you will find that the former this points to not foo itself, but the window object of the current page, the latter actually points to foo. Why?
In fact, this involves an important feature of JavaScript, the so-called "closure ". The concept of closure is not complicated, but it is not easy to say in one or two sentences. I will discuss the most important feature of Javascript in future articles. Now, I want to tell you that the scope in JavaScript becomes very important because of the existence of closures.
The so-called scope is simply the environment in which a function is created. The value of this variable, if not specified, is the current scope of the function.
In the previous example, the foo () function is in the global scope (here the window object), so the value of this is the current window object. In the form of new foo (), a copy of foo () is created and operated on the copy. Therefore, this is foo ().
This may be a bit abstract. Let's take a look at the actual example:
<input type="button" id="aButton" value="demo" onclick="" /><script type="text/javascript">function demo() { this.value = Math.random();}</script>
If you call the demo () function directly, the program will report an error. Because the demo function is defined in the window object, the demo owner (scope) is window, And the demo this is window. Window does not have the value attribute, so an error is returned.
If we add a copy of the function to an HTML element by creating a copy, the owner of the function becomes the element. this also refers to this element:
document.getElementById("aButton").onclick = demo;
In this way, the onlick attribute of aButton is set to a copy of demo (), and this also points to aButton.
You can even create different function copies for different HTML elements. The owner of each copy is a corresponding HTML element, and their respective this points to their owner, which will not cause confusion.
However, if you define the onlick event of an element as follows:
<input type="button" id="aButton" value="demo" onclick="demo()" />
After clicking this button, you will find that the program returns an error -- this points to the window again!
In fact, this method does not create a function for the program, but only references this function.
Let's take a look at the difference.
How to Create a function copy:
<input type="button" id="aButton" value="demo" /><script type="text/javascript">var button = document.getElementById("aButton");function demo() { this.value = Math.random();}button.onclick= demo;alert(button.onclick);</script>
The output is as follows:
function demo() { this.value = Math.random();}
Use the function reference method:
<input type="button" id="aButton" value="demo" onclick="demo()" /><script type="text/javascript">var button = document.getElementById("aButton");function demo() { this.value = Math.random();}alert(button.onclick);</script>
The output is as follows:
function onclick() { demo();}
In this way, we can see the difference. In the function reference method, The onclick event only calls the demo () function directly, while the scope of the demo () function is still the window object, so this still points to the window.
This raises another question: Since the function copy is so useful, why do we still need the function reference method? The answer is performance. Each time a function is created, the program allocates a certain amount of memory for the function copy. In practical applications, most functions are not always called, so this part of memory is wasted. In the function reference mode, the program only allocates memory to the function body, while the reference only allocates pointers, which is much more efficient. Programmer, mainly economical.
So let's look at a better solution:
<script type="text/javascript">function demo(obj) { obj.value = Math.random();}</script><input type="button" value="demo" onclick="demo(this)" /><input type="button" value="demo" onclick="demo(this)" /><input type="button" value="demo" onclick="demo(this)" />
In this way, both efficiency and demand can be taken into account.
This point
Because JavaScript is bound at runtime, this in JavaScript can be a global object, current object, or any object, depending entirely on the function call method. Functions in JavaScript can be called in the following ways: as an object method call, as a function call, as a constructor call, and using apply or call. As the saying goes, words are not as good as tables, but tables are not. What does JavaScript this point to for a better understanding? The following is an illustration:
I call it JavaScript this decision tree (in non-strict mode ). The following example shows how this graph helps us determine this:
Var point = {x: 0, y: 0, moveTo: function (x, y) {this. x = this. x + x; this. y = this. y + y ;}}; // decision tree interpretation: point. the moveTo () function is not called by the new function, and no decision is made. // The dot (.) function is used (.) to. the call object before moveTo, that is, pointpoint. moveTo (); // this is bound to the current object, that is, the point object.
The process of determining the point. moveTo () function in "JavaScript this Decision Tree" is as follows:
1) is the point. moveTo function called using new? This is obviously not. Go to the "no" branch, that is, whether the function is called using dot ?;
2) The point. moveTo function is called with dot (.), that is, it enters the "yes" branch, that is, this points to the object point in point. moveTo;
The parsing diagram of the point. moveTo function's this point is shown in:
Let's look at the following code:
Function func (x) {this. x = x;} func (5); // this is the Global Object window, and x is the global variable. // decision tree parsing: Is the func () function called with new? Is it true that the function that enters func () is called using dot? Otherwise, this points to the Global Object windowx; // x => 5
The process of determining the func () function in the JavaScript this decision tree is as follows:
1) func (5) does function calling use new? This is obviously not. Go to the "no" branch, that is, whether the function is called using dot ?;
2) func (5) the function does not use dot (.) to call, that is, to enter the "no" branch, where this points to the global variable window, then this. x is actually a window. x;
The parsing diagram of the point this of the func function is shown in:
The following is a complex example of direct function calling:
Var point = {x: 0, y: 0, moveTo: function (x, y) {// internal function var moveX = function (x) {this. x = x; // What does this point? Window}; // internal function var moveY = function (y) {this. y = y; // What does this point? Window}; moveX (x); moveY (y) ;}}; point. moveTo (1, 1); point. x; // => 0 point. y; // => 0 x; // => 1 y; // => 1
Point. the moveTo () function actually calls the moveX () and moveY () functions internally, moveX () the process of this determination in the JavaScript this decision tree is as follows:
1) Does moveX (1) Use new to call a function? This is obviously not. Go to the "no" branch, that is, whether the function is called using dot ?;
2) moveX (1) the function does not use dot (.) to call, that is, to enter the "no" branch, where this points to the global variable window, then this. x is actually a window. x;
The following is an example of a constructor call:
Function Point (x, y) {this. x = x; // this? This. y = y; // this? } Var np = new Point (1, 1); np. x; // 1var p = Point (2, 2); p. x; // error, p is an empty object undefinedwindow. x; // 2
The Point () function in var np = new Point () this determines the process in the JavaScript this decision tree as follows:
1) is var np = new Point () called with new? It is obvious that the "yes" branch is entered, that is, this points to np;
2) then this. x = 1, that is, np. x = 1;
The process of this in the JavaScript this decision tree of the Point () function in var p = Point () is as follows:
1) var p = Point (2, 2) is a call made with new? This is obviously not. Go to the "no" branch, that is, whether the function is called using dot ?;
2) isn't the Point (2, 2) function called with dot? If it is determined to be "no", it indicates that this points to the global variable window, so this. x is actually window. x;
3) this. x = 2 is window. x = 2.
Finally, let's take a look at the call and apply call examples of the function:
Function Point (x, y) {this. x = x; this. y = y; this. moveTo = function (x, y) {this. x = x; this. y = y ;}} var p1 = new Point (0, 0); var p2 = {x: 0, y: 0}; p1.moveTo. apply (p2, [10, 10]); // apply is actually p2.moveTo (10, 10) p2.x // 10
The p1.moveTo. apply (p2, []) function determines in the JavaScript this decision tree as follows:
We know that the apply and call methods are extremely powerful. They allow switching the context of function execution, that is, the objects bound to this. P1.moveTo. apply (p2, [10, 10]) is actually p2.moveTo (10, 10 ). Then p2.moveTo (10, 10) can be interpreted:
1) Does p2.moveTo (10, 10) use new to call a function? This is obviously not. Go to the "no" branch, that is, whether the function is called using dot ?;
2) The p2.moveTo () function uses dot (.) to call, enter the "yes" branch, that is, this points to p2.moveTo (10, 10. the previous object p2, so p2.x = 10;
For the JavaScript function execution environment process, the description in the IBM developerworks document library is very good. The excerpt is as follows:
"Functions in JavaScript can be executed as common functions or methods of objects, which is the main cause of this's rich meaning. When a function is executed, an execution environment (ExecutionContext) is created, and all the actions of the function occur in this execution environment. When the execution environment is built, JavaScript will first create the arguments variable, it contains the parameters passed in when the function is called. Next, create a scope chain. Then initialize the variable. First, initialize the form parameter table of the function. The value is the value corresponding to the arguments variable. If there is no corresponding value in the arguments variable, the form parameter is initialized to undefined. If the function contains internal functions, initialize these internal functions. If no, continue to initialize the local variables defined in the function. Note that these variables are initialized to undefined at this time, and the value assignment operation is successful after the ExecutionContext is created, the function is executed only when it is executed. This is very important for us to understand the variable scope in JavaScript. In view of the length, we will not discuss this topic here. Assign a value to this variable. As mentioned above, this global object and current object will be assigned according to the function call method. At this point, the execution environment (ExecutionContext) of the function is successfully created, and the function starts to be executed row by row. All required variables are read from the previously created execution environment (ExecutionContext ."
Understanding this section will be helpful for understanding Javascript Functions.