Detailed the this pointer in JavaScript

Source: Internet
Author: User
Tags tag name tagname

Objective

JavaScript is an object-based dynamic language, which means that everything is an object, and a typical example is that functions are also considered ordinary objects. JavaScript can implement object-oriented programming through certain design patterns, where this "pointer" is an important feature of implementing object-oriented. But this is also a very easy-to-understand and wrong-to-use feature in JavaScript. This is especially true for comrades who have been exposed to static language for a long time.

Example description

Let's take a look at one of the simplest examples:

<Type= "Text/javascript">
"Kevin Yang";
function Sayhi () {
Alert ("Hello, my name is called" + name);
}
Sayhi ();
</Script>

This code is very simple, we define a global string object name and function object Sayhi. The run will pop up a greeting dialog box, "Hello, my name is Kevin Yang".

Let's change this code a little bit:

<Type= "Text/javascript">
"Kevin Yang";
function Sayhi () {
Alert (this.name);
}
Sayhi ();
</Script>

The difference between this code and the previous code is that the Sayhi function adds the this. prefix when using name. The result is the same as the one above. This indicates that the THIS.name reference is also a global name object.

At the beginning we did not say that the function is also an ordinary object, it can be used as a normal variable. Let's change the code above:

<Type= "Text/javascript">
"Kevin Yang";
function Sayhi () {
Alert (this.name);
}
var person = {};
Person.sayhello = Sayhi;
Person.sayhello ();
</Script>

This time, we created a global object person and assigned the Sayhi function object to the SayHello property of the Person object. The results of the operation are as follows:

This time the content of greeting is a little unreasonable, we found that THIS.name has become undefined. This means that the THIS.name object has not been found when executing inside the SayHello function. What if we redefine the person object and add a name attribute to it?

var person = {Name:"Marry"};

Run code to find the "person" of greeting changed:

Did you see some way out?

Guiding principles for judging this pointer

In JavaScript, the this pointer represents the owner of the object executing the current code.

In the example above, we can see that for the first time, we define a global function object Sayhi and execute this function, and the function internally uses the This keyword, then the object that executes this line of code is SAYHI (the embodiment of all objects), Sayhi is defined in the global scope. In fact, the so-called global object in JavaScript is nothing more than a property defined under the root object of window. Therefore, the owner of the Sayhi is the Window object. That is, under global scope, you can refer to the object by using name directly, or you can refer to the same object by Window.name. Thus this.name can be translated into Window.name .

Take a look at the second example of this. We define the object of a person and define its SayHello property to point to the Sayhi global object. So this time, When we run Person.sayhello, this is where the code belongs to the object is SayHello (in fact, Sayhi and SayHello is just like two pointers, pointing to the object is actually the same), and the owner of the SayHello object is the person. For the first time, there is no Name attribute in person, so the dialog box that pops up is this.name refers to the undefined object (all variables in JavaScript that are declared but not defined all point to the undefined object ) And the second time we add the name attribute when we define the person, then the nature that this.name points to is our defined string.

Having understood what is said above, we have transformed the last example above into an object-oriented code.

<script type = "Text/javascript" > 
var name = " Kevin Yang ";
function Sayhi () {
Alert ( Hello, my name is "+ this.name);
}
function person (name) {
this.name = name;
}
Person.prototype.sayHello = Sayhi;
var marry = new person ( "marry");
Marry.sayhello ();
var kevin = new person ( Kevin.sayhello ();
</script>

In the above code, we define a person's "class" (actually an object), and then define the SayHello property in the prototype of the class (The class prototype is equivalent to a static member variable in C + + ), which points to the global Sayhi object. Running the code we can see that both marry and Kevin have succeeded in saying "Hello" to us.

There are two points in this code that need to be considered, one is new we are familiar with, but what does new do here? The other is, why is this pointer pointing correctly to marry and Kevin objects when SayHello is executed here?

Let's re-"translate" the actions above that define "class" and instantiate class objects:

<script type= "Text/javascript" Span class= "KWRD" >> 
var name = "Kevin Yang";
function Sayhi () {
Alert ( Hello, my name is "+ this.name);
}
function person (name) {
var this;
this.name = name;
return this;
}
Person.prototype.sayHello = Sayhi;
var marry = person ( "marry");
Marry.sayhello ();
var Kevin = person ( Kevin.sayhello ();
</script>

Of course, this code does not execute correctly, but it can help you understand the process better.

When we instantiate a "class" object using the New keyword, the JavaScript engine defines a new object inside the object and stores it in the this pointer. All the code inside this object that uses this is actually pointing to the new object. For example, this.name = name, the name object in the parameter is actually assigned the value to the newly created object. After the function object is executed, the JavaScript engine returns the object to you, so the Marry variable gets the name of the object "Marry", and the Name property of the object that the Kevin variable gets is really "Kevin".

To manipulate the this pointer explicitly

In the above example of object-oriented programming, we see that in the case of the new operator, it seems that the point of this is not consistent with the guiding principles described in our previous section. The this pointer does not point to the owner of marry or Kevin, but to the marry and Kevin variables themselves.

In fact, if you understand what a pointer is, then you know that, since it is a pointer, you can certainly change the object it points to. But the JavaScript engine does not allow us to write code to do such things, that is, in JavaScript, you can not directly write this = someobj code. The JavaScript engine allows us to explicitly specify the object that this pointer refers to in the following two ways:

1. With the new operator, the JavaScript engine returns the this pointer to the assigned variable a (corresponding to the example above is the marry and Kevin variables), at which point A and this pointer refer to the same object, that is, a = = this. The procedure is described in the pseudo-code above.

2. Using the Function.apply or Function.call prototype method, we can refer to the object of this pointer as a parameter in the form of parameters, this time, the function of the internal use of the this pointer is passed in the parameters.

Note that the guidelines mentioned in the previous section are no longer applicable for cases where this pointer is explicitly specified.

A situation prone to misuse

After understanding the this pointer, let's take a look at some cases where this pointer is easily misused.

Example of an event handler for inline-bound DOM elements

<Type= "Text/javascript">
function Sayhi () {
Alert (this.tagname);

</Script>
<IDtypevalueonclick= "sayhi ()">

In this example code, we bind the button's Click event and expect to print the tag name of the clicked Element in the popup dialog box. But the result is:

That is, the this pointer does not point to the INPUT element. This is because when you use an inline-bound DOM element's event-handler function, the following code is actually executed:

<Type= "Text/javascript">    
document.getElementById (function () {
Sayhi ();
}
</Script>

In this case , the ownership of the Sayhi function object does not take place or is owned by window. with a set of guiding principles above, we can understand why this.tagname is undefined.

So what if we're going to quote the element itself?

We know that the onclick function belongs to the btntest element, so inside this function, the this pointer points to this DOM object, so we just need to pass this as a parameter to the Sayhi.

<Type= "Text/javascript">
function Sayhi (EL) {
Alert ("The element that is currently clicked is" + El.tagname);
}
</Script>
<IDtypevalueonclick= "Sayhi (This)">

The equivalent code is as follows:

<Type= "Text/javascript"
document.getElementById (function () {
Sayhi (this);
}
</Script>

Example 2--the this pointer is missing due to a temporary variable

<script type = "Text/javascript" > 
var Utility = {
decode:< Span class= "KWRD" >function (str) {
return unescape (str);
},
GetCookie: function (key) {
//... Omit the code that extracts the cookie string
var value = return this.decode (value);
}
};
Alert (Utility.getcookie ( </ Script>

When we write a little bit of the size of the JS library, we usually encapsulate a utility class, and then use some of the usual functions as properties of the utility class, such as the GetCookie function and decoding function that clients often use. If each function is independent of each other, then fortunately, the problem is that functions sometimes refer to each other. For example, the GetCookie function above will return after decode the string extracted from the Document.cookie. If we call through Utility.getcookie, then there is no problem, we know that the this pointer inside the GetCookie points to the utility object, and the utility object contains the Decode property. The code can be executed successfully.

But has someone accidentally used utility objects like this?

<Type= "Text/javascript">
function showuseridentity () {
Save the GetCookie function to a local variable, as the following will often be used
var getcookie = Utility.getcookie;
Alert (GetCookie ("Identity"));
}
Showuseridentity ();
</Script>

Running the code at this time throws an exception "This.decode is not a function". Using the guidelines we've described above, it's good to understand, because at this point the Utility.getcookie object is assigned to the temporary variable GetCookie, and the temporary variable belongs to the Window object--only the outside cannot be directly referenced, only the JavaScript engine is visible-- So the this pointer inside the GetCookie function points to the Window object, and the Window object does not define a decode function object, so the exception is thrown.

This problem is due to the introduction of temporary variables resulting from the transfer of this pointer. There are several ways to solve this problem:

    • No temporary variables are introduced, each use is called with Utility.getcookie
    • The GetCookie function internally uses Utility.decode to explicitly reference the Decode object without an implicit reference through the this pointer (if the utility is an instantiated object, which is generated by new, then this method is not available)
    • Use the funtion.apply or Function.call function to specify the this pointer

The first two kinds are better understood, the third need to mention. It is because the pointer to this is easily lost, so JavaScript provides two similar functions, apply and call, to allow the function to explicitly specify the this pointer when called.

The fix code is as follows:

<Type= "Text/javascript">
function showuseridentity () {
Save the GetCookie function to a local variable, as the following will often be used
var getcookie = Utility.getcookie;
Alert (Getcookie.call (Utility,"identity"));
Alert (getcookie.apply (utility,["Identity"));
}
Showuseridentity ();
</Script>

Call and apply have only grammatical differences and no functional differences.

Example 3--the this pointer is missing when the function is passed

Let's take a look at the problem code first:

<Type= "Text/javascript">
var person = {
Name:"Kevin Yang",
Sayhi:function () {
Alert ("Hello, I am" +this.name);
}
}
SetTimeout (person.sayhi,5000);
</Script>

This code expects to say hello to visitors 5 seconds after the visitor enters the page. The settimeout function takes a function as a parameter and executes the function at the specified trigger time. However, when we waited for 5 seconds, the popup dialog showed the this.name is undefined.

In fact, this problem is similar to the one in the previous example, because of the problem caused by the temporary variable. When we execute a function, if the function has parameters, then the JavaScript engine creates a temporary variable and copies the passed in Parameters (note that JavaScript is a value-passing, no reference-passing concept) to this temporary variable. That is, the whole process is just like the above we define a getcookie temporary variable, and then assign the Utility.getcookie to this temporary variable. Just in this example, it is easy to ignore the bug caused by the temporary variable.

Function Object Pass Parameter

The problem of this pointer loss caused by the function being passed as a parameter is now solved by many frameworks.

Prototype solution--use the Bind method to encapsulate the function and return the encapsulated object before the parameter is passed

<Type= "Text/javascript">
var person = {
Name:"Kevin Yang",
Sayhi:function () {
Alert ("Hello, I am" +this.name);
}
}
var boundfunc = Person.sayHi.bind (Person,person.sayhi);
SetTimeout (boundfunc,5000);
</Script>

The implementation of the Bind method is actually using JavaScript, another advanced feature--closures. Let's take a look at the source code:

function bind () {

This
Object = Args.shift ();
function () {
Return __method.apply (object, Args.concat ($A (arguments)));
}
}

The this pointer is first stored inside the function temporary variable, and then the temporary variable is referenced in the returned function object to form a closure.

Microsoft's AJAX Library provides a solution--building a delegate object

<Type= "Text/javascript">
var person = {
Name:"Kevin Yang",
Sayhi:function () {
Alert ("Hello, I am" +this.name);
}

var boundfunc = function.createdelegate (Person,person.sayhi);
SetTimeout (boundfunc,5000);
</Script>

In essence, the prototype is the same way.

The well-known ExtJS library solution uses the same approach as Microsoft.

(go) Explain the this pointer in JavaScript

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.