4 issues related to this, new, call and apply
The principle of this pointer is a very complicated question, and if we illustrate this from the implementation mechanism of this in JavaScript, many friends may become more and more confused, so this article is going to change the idea of the this pointer from an application perspective, It is more realistic to understand this pointer from this perspective.
Let's take a look at how the this pointer is used in the Java language, the following code:
public class Person {
private String name;
Private String sex;
private int age;
Private String job;
Public person (string name, string sex, int age, string job) {
Super ();
THIS.name = name;
This.sex = sex;
This.age = age;
This.job = job;
}
private void Showperson () {
System.out.println ("Name:" + this.name);
System.out.println ("Sex:" + this.sex);
System.out.println ("Age:" + this.age);
System.out.println ("Work:" + this.job);
}
public void Printinfo () {
This.showperson ();
}
public static void Main (string[] args) {
Person man = new Person ("Ma", "Male", 46, "chairman");
Person.printinfo ();
}
}
Name: Ma Yun
Sex: Male
Age: 46
Work: Chairman
The above code executes without any problems, I modify this code below, add a static method, the static method uses the this pointer to invoke the properties in the class, as shown in the following figure:
We found that the IDE reported a syntax error, "cannot use this in a static context", the this pointer cannot be used in static contexts in the Java language.
There are two important concepts in object-oriented programming: One is a class, the other is an instantiated object, a class is an abstract concept, with an image metaphor, a class is like a stencil, and an instantiated object is a product made from this mold, Instantiating an object is the real thing we need, and the class has a very close relationship with the instantiated object, but the function of the class in use is definitely not a substitute for the instantiation object, like the relationship between the mold and the mold-making product, and the use of the two is different.
With the above code we can see that the this pointer can only be used in the instantiated object in the Java language, the this pointer equals this instantiated object, and this is followed by the dot operator. The thing behind the dot operator is what this has, for example: Name, job, hand, foot, and so on.
Actually the concept of this pointer in JavaScript is also an instantiated object , which is consistent with the this pointer in the Java language. But the this pointer in JavaScript is more difficult to understand than this in Java, and the root cause I personally think there are three reasons:
reason one: JavaScript is a functional programming language, and the weird is that it also has this pointer, which shows that the functional programming language is also an object-oriented language, and that the specific point of JavaScript the function in the programming language is a higher order function that can be passed as an object, while JavaScript The function can also be used as a constructor, which creates an instantiated object, which results in the method executing this the point of the pointer changes constantly and is difficult to control.
reason two: JavaScript the global scope in pointers have a great impact by the top Java The example we see, this the pointer only uses the new operator will not take effect, but JavaScript This in the in the absence of a new operation will also take effect, this time this tend to point to global object window .
reason three: JavaScript Call in and Apply operators are free to change this point, this looks very flexible, but this perverse approach undermines our understanding of this the intention of the pointer, but also makes it difficult to understand when writing code this the real point
The above three reasons are against the traditional this pointer to use the method, they have different from the traditional this principle of understanding, and in the actual development of the three reasons are often intertwined, which is even more confusing, today I want to clarify this idea for everyone, In fact, the this pointer in JavaScript has a set of inherent logic, and we understand that this logic will be able to accurately grasp the use of this pointer.
Let's take a look at the following code:
<script type= "Text/javascript" >
THIS.A = "AAA";
Console.log (a);//aaa
Console.log (THIS.A);//aaa
Console.log (WINDOW.A);//aaa
Console.log (this);//Window
Console.log (window);//Window
Console.log (this = = window);/True
Console.log (this = = window);/True
</script>
We can use the this pointer directly in the script tag, the This pointer is the window object, and we see that they are equal even with the three equals. Global scopes often interfere with our understanding of the nature of the JavaScript language, which is essentially:
in JavaScript the global scope in the language can be understood as window object, remember window is an object rather than a class, which means window is an instantiated object that is instantiated when the page is loaded by JavaScript engine completed, the elements of the entire page were condensed into this window object because programmers cannot control and manipulate this instantiation process through the programming language, so we didn't build this one at development time . The sense of the pointer often ignores it, which is interfering with our understanding of this in the Code pointer pointing to window of the situation.
The nature of the disturbances is also related to the use of function, let's look at the following code:
<script type= "Text/javascript" >
function Ftn01 () {
Console.log ("I am ftn01!");
}
var ftn02 = function () {
Console.log ("I am ftn02!");
}
</script>
Above are the two ways we use to define functions, the first way to define a function in a JavaScript language is called a declaration function, and the second way to define a function is called a function expression , which we usually consider to be equivalent. , but they are really different, and this difference often makes us confuse the use of this pointer, and we'll look at the following code:
<script type= "Text/javascript" >
Console.log (Ftn01);//ftn01 () Note: Under Firebug, this print result can be clicked and the definition of function will be displayed after clicking.
Console.log (FTN02);//undefined
function Ftn01 () {
Console.log ("I am ftn01!");
}
var ftn02 = function () {
Console.log ("I am ftn02!");
}
</script>
This is another part of the code is not executed sequentially, first look at the FTN02, the print result is undefined,undefined I mentioned in the previous article, in the memory of the stack area has the name of the variable, but there is no stack area of variable values, while the heap area is not a specific object, This is the JavaScript engine in the preprocessing (the group Oriental says preprocessing is more accurate than preload, I agree with him that later in the article I have written for preprocessing) scan variable definition, but Ftn01 's print results are surprising, since the finished function is printed out and the code does not execute sequentially, This only illustrates one problem:
in JavaScript language defines functions by declaring functions, JavaScript The engine completes the function definition and assignment operations during preprocessing, where I add JavaScript the characteristics of pretreatment, in fact, preprocessing is related to the implementation of the environment, in the last article I talked about the implementation of the environment there are two major categories: the global execution environment and local execution environment, the implementation environment is reflected through the context variables, in fact, this process is completed before the function execution, preprocessing is the construction of the implementation of In a word, the main purpose of preprocessing and constructing the execution environment is to define the variables and distinguish the boundary of the variables, but in the global scope or global variable preprocessing, the declaration function will complete the variable definition and assignment operation simultaneously, so we see the result of the code running above. Since the declaration function is done in the global scope construct, declaring the function is a property of the Window object, which explains why we declare the function to be the end of the Window object , regardless of where we declare the function.
On the writing of function expressions there are secrets to explore, so let's look at the following code:
<script type= "Text/javascript" >
function Ftn03 () {
var ftn04 = function () {
Console.log (this);//Window
};
Ftn04 ();
}
Ftn03 ();
</script>
The results of the operation we found that ftn04 although in the ftn03 scope, but the implementation of the this pointer inside it is also point to window, in fact, the expression of the function of most of us prefer to write inside the function, because the declaration function of this point to window this is not a secret, But the this pointer to the function expression is often overlooked by us, especially when it is written inside another function.
actually in JavaScript any anonymous function in the language belongs to window. objects, which are also defined and assigned when the global scope is constructed, but an anonymous function is a function variable without a name, but it returns its own memory address when the anonymous function is defined, and if a variable at this time receives the memory address, then the anonymous function can be used in the program. Because the anonymous function is also defined and assigned when the global execution environment is constructed, the this point of the anonymous function is also the window object, so the code at the top of the execution ftn04 this Also points to window, because JavaScript variable names, regardless of the scope that is valid, are fixed when the stored function of the heap area is in the global execution environment, and the name of the variable is just a reference.
This is broken, this is pointing to window, so how can we change it in the end?
At the beginning of this article I said the secret of this, which is to point to the instantiated object , so many cases mentioned before this point to window, because these times only a single instantiation operation, And this instantiation is instantiating the Window object, so this is all pointing to window. We're going to turn this from window to something else, we have to get the function instantiated, so how do we get JavaScript's function instantiated? The answer is to use the new operator. Let's look at the following code:
<script type= "Text/javascript" >
var obj = {
Name: "Sharpxiajun",
Job: "Software",
Show:function () {
Console.log ("Name:" + THIS.name +); Job: "+ this.job";
Console.log (this);//Object {name= "Sharpxiajun", job= "Software", Show=function ()}
}
};
var otherobj = new Object ();
Otherobj.name = "XTQ";
Otherobj.job = "good";
Otherobj.show = function () {
Console.log ("Name:" + THIS.name +); Job: "+ this.job";
Console.log (this);//Object {name= "xtq", job= "good", Show=function ()}
};
Obj.show ();//name:sharpxiajun; Job:software
Otherobj.show ();//name:xtq; Job:good
</script>
This is an example of the use of this in my last article, which is one of the writing we all love to write, and the this pointer is not pointing to window, but to an instance of object, Firebug's display makes many people wonder, in fact, object is an object-oriented class, The curly braces are the instance objects, i.e. obj and otherobj. The way in Javascript to define objects in a literal way is shorthand for new object, which is equivalent to reducing the amount of code written so that even without the new operation literal definition is the new operator, this is changed by new The pointers are indeed the truth of the breach.
I'll use JavaScript to rewrite the Java-defined class at the beginning of this article, with the following code:
<script type= "Text/javascript" >
function Person (name,sex,age,job) {
THIS.name = name;
This.sex = sex;
This.age = age;
This.job = job;
This.showperson = function () {
Console.log ("Name:" + this.name);
Console.log ("Sex:" + this.sex);
Console.log ("Age:" + this.age);
Console.log ("Work:" + this.job);
Console.log (this);/person {name= "Ma", sex= "male", age=46, More ...}
}
}
var person = new Person ("Ma", "Male", 46, "chairman");
Person.showperson ();
</script>
Looking at the this pointer's printing, the class becomes a person, which indicates that a function is equivalent to defining a class, in JavaScript the function is too much,function as a function and as an object, a function is also used as a constructor, and the JavaScript constructor I often think is to bring the class and the constructor together, of course, in JavaScript There is no concept of a class in the language specification, but my understanding can be a difference between a constructor and a normal function, which makes it easier to understand .
Below I post an explanation of the new operator in JavaScript advanced programming:
New operator causes the constructor to change the following:
1. Create a new object;
2. Assign the scope of the constructor to the new object (so this points to the new object);
3. Execute the code in the constructor (add attributes for this new object);
4. return new Object
About the 2nd is very easy to confuse, for example in the previous example of obj and Otherobj,obj.show (), inside this point to obj, my previous article on a simple identification this method is to see the method call before the object is which this is pointing to which, In fact, this process can also be understood, in the Global Execution Environment window is the context object, then in obj, the local scope is represented by obj, this window's understanding is consistent.
4th also focus on, remember that the constructor is new operation, to let new normal function is best not to write return in the constructor, no return of the constructor is based on the above four points, with the return situation is complicated, this knowledge I will speak prototype time.
JavaScript also has a way to change the this pointer, which is the call method and the Apply method, and the call and apply methods have the same effect, that is, when the parameters are different, the first parameter of call and apply is the same, but the following arguments are different. Apply the second argument is the array, and call has many arguments after the second argument starts. What is the role of call and apply, this is important, the focus is described as follows:
Call and Apply is to change the scope of a function (some books are called changing the context of a function)
This description we refer to the second of the new operator above:
assigns the scope of the constructor to the new object (therefore this point to the new object);
Call and Apply is will this the pointer points to the first parameter of the method.
Let's look at the following code:
<script type= "Text/javascript" >
var name = "Sharpxiajun";
function FTN (name) {
Console.log (name);
Console.log (this.name);
Console.log (this);
}
FTN ("101");
var obj = {
Name: "XTQ"
};
Ftn.call (obj, "102");
/*
* The results are as follows:
*101
T002.html (line 73rd)
Sharpxiajun
T002.html (line 74th)
Window t002.html
T002.html (line 75th)
T002.html (line 73rd)
Xtq
T002.html (line 74th)
Object {name= "XTQ"}
* */
</script>
We see that apply and call change the point of this, which is important in development, we are often puzzled by this, the root cause of confusion I mentioned above, here I talk about the surface reasons:
The superficial reason is that we define the literal representation of objects using objects, which we can easily know in simple representations . point to the object itself, but the object will have a method, the parameter of the method may be a function, and the definition of this function may also use this pointer, if the incoming function is not instantiated and instantiated, this the point is different, and sometimes we want to pass this in the incoming function. point to an external function or point to the defined object itself, these messy situations use intertwined to cause this becomes very complicated, and the result becomes muddled.
In fact, the above situation is also traceable, in the definition of the object in the method passed into the function as an example:
Case One: The incoming parameter is the alias of the function, then the function of this is to point to window ;
Scenario Two: The incoming parameter is the new over the constructor, then this is to point to the instantiated object itself;
Case Three: if we want to put this in the function object being passed in pointer to an object that is defined by an external literal, then we use the Apply and Call
We can see through the code that my conclusion, the code is as follows:
<script type= "Text/javascript" >
var name = "I am Window";
var obj = {
Name: "Sharpxiajun",
Job: "Software",
Ftn01:function (obj) {
Obj.show ();
},
Ftn02:function (FTN) {
FTN ();
},
Ftn03:function (FTN) {
Ftn.call (this);
}
};
function person (name) {
THIS.name = name;
This.show = function () {
Console.log ("Name:" + this.name);
Console.log (this);
}
}
var p = new person (' person ');
Obj.ftn01 (P);
OBJ.FTN02 (function () {
Console.log (this.name);
Console.log (this);
});
Obj.ftn03 (function () {
Console.log (this.name);
Console.log (this);
});
</script>
The results are as follows:
Finally, let's summarize:
If you are in JavaScript The language doesn't pass new. (including object literal definition), call and Apply change the function of this pointer, function of this pointers are pointing to window of the .