Understanding JavaScript series (13) This? Yes, this!

Source: Internet
Author: User

Introduction
In this article, we will discuss more details directly related to the execution context. The topic of the discussion is the this keyword. Practice has proved that this topic is very difficult, and this often occurs in different execution contexts.

Many programmers tend to think that in programming languages, the this keyword is closely related to object-oriented program development and completely points to the newly created object by the constructor. This is also implemented in the ECMAScript specification, but as we will see, in ECMAScript, this is not limited to pointing only to newly created objects.

Dmitry A. Soshnikov with the help of Stoyan Stefanov
Release: 2010-03-07
Http://dmitrysoshnikov.com/ecmascript/chapter-3-this/

Original Russian: Dmitry A. Soshnikov
Corrected: Zeroglif
Release;
Updated: 2010-03-07
Http://dmitrysoshnikov.com/ecmascript/ru-chapter-3-this/

The vast majority of content reference: http://www.denisdeng.com /? P = 900
Some sentences refer to: Chinese Translation of justin
Copy code
For more details, what is this in ECMAScript?

Definition
This is an attribute in the execution context:
Copy codeThe Code is as follows:
ActiveExecutionContext = {
VO :{...},
This: thisValue
};

VO is the variable object discussed in the previous chapter.

This is directly related to the type of executable code in the context. The value of this is determined when the context is entered and remains unchanged during context running.

Let's take a closer look at these cases:

This in Global Code
Everything is simple here. In the global code, this is always a global object, which may be referenced indirectly.
Copy codeThe Code is as follows:
// Display the attributes of the global object.
This. a = 10; // global. a = 10
Alert (a); // 10

// Implicitly assigns a value to a non-identifier
B = 20;
Alert (this. B); // 20

// It is also implicitly declared through variable Declaration
// Because the global context variable object is the global object itself
Var c = 30;
Alert (this. c); // 30

This in Function Code
It is interesting to use this in function code, which is difficult and can cause many problems.

In this type of code, the primary feature (or perhaps the most important) of this value is that it is not statically bound to a function.

As we mentioned above, this is determined when the context is entered. In a function code, this value is completely different each time.

In any case, the this value remains unchanged during code runtime, that is, because it is not a variable, it is impossible to assign a new value to it (on the contrary, in the Python programming language, it is clearly defined as the object itself and can be changed continuously during runtime ).
Copy codeThe Code is as follows:
Var foo = {x: 10 };

Var bar = {
X: 20,
Test: function (){

Alert (this = bar); // true
Alert (this. x); // 20

This = foo; // error. The value of this cannot be changed at any time.

Alert (this. x); // if no error occurs, it should be 10 instead of 20

}

};

// When entering the context
// This is treated as a bar object.
// Determined as "bar" object; why so-will
// Be discussed below in detail

Bar. test (); // true, 20

Foo. test = bar. test;

// However, this is still not foo
// Although the same function is called

Foo. test (); // false, 10

There are several factors that affect the change of this value in the function code:

First, in common function calls, this is provided by the caller who activates the context code, that is, the parent context of the called function (parent context ). This depends on how the function is called.

To accurately determine this value under any circumstances, it is necessary to understand and remember this important point. It is exactly the way the function is called that affects the value of this in the context of the call, and there is nothing else (we can see in some articles, even in books about javascript, they claim: "this value depends on how the function is defined. If it is a global function, this is set as a global object. If the function is an object method, this always points to this object. -This is definitely incorrect "). Continue to our topic. We can see that even normal global functions are activated in Different calling methods. These different calling methods lead to different this values.
Copy codeThe Code is as follows:
Function foo (){
Alert (this );
}

Foo (); // global

Alert (foo = foo. prototype. constructor); // true

// But this is different for different call expressions of the same function.

Foo. prototype. constructor (); // foo. prototype

It is possible to call functions as some object-defined methods, but this will not be set as this object.
Copy codeThe Code is as follows:
Var foo = {
Bar: function (){
Alert (this );
Alert (this = foo );
}
};

Foo. bar (); // foo, true

Var exampleFunc = foo. bar;

Alert (exampleFunc === foo. bar); // true

// Once again, this is different for different call expressions of the same function

ExampleFunc (); // global, false

So how does the function call affect the value of this? To fully understand the determination of this value, you need to analyze one of its internal types in detail-Reference type ).

Reference type)
With pseudo-code, we can represent the value of the reference type as an object with two properties-base (that is, the object with the property) and propertyName in base.
Copy codeThe Code is as follows:
Var valueOfReferenceType = {
Base: <base object>,
PropertyName: <property name>
};

There are only two types of reference values:

When we process a identifier
Or an attribute accessor
The processing process of the identifier is discussed in detail in the next article. Here we only need to know that in the return value of this algorithm, always a value of the reference type (which is important to this ).

The identifier is a variable name, function name, function parameter name, and a property name not recognized in the global object. For example, the following Identifier value:
Copy codeThe Code is as follows:
Var foo = 10;
Function bar (){}

In the intermediate result of the operation, the value of the reference type is as follows:
Copy codeThe Code is as follows:
Var fooReference = {
Base: global,
PropertyName: 'foo'
};

Var barReference = {
Base: global,
PropertyName: 'bar'
};

To get the true value of an object from the reference type, the GetValue method in pseudo-code can be described as follows:
Copy codeThe Code is as follows:
Function GetValue (value ){

If (Type (value )! = Reference ){
Return value;
}

Var base = GetBase (value );

If (base = null ){
Throw new ReferenceError;
}

Return base. [[Get] (GetPropertyName (value ));

}

The internal [[Get] method returns the true values of object attributes, including the analysis of inherited attributes in the prototype chain.
Copy codeThe Code is as follows:
GetValue (fooReference); // 10
GetValue (barReference); // function object "bar"

All attribute accessors should be familiar with this feature. It has two variants: The dot (.) syntax (in this case, the attribute name is a correct identifier and is known in advance), or the bracket syntax ([]).
Copy codeThe Code is as follows:
Foo. bar ();
Foo ['bar'] ();

In the return value of intermediate calculation, we have a value of the reference type.
Copy codeThe Code is as follows:
Var fooBarReference = {
Base: foo,
PropertyName: 'bar'
};

GetValue (fooBarReference); // function object "bar"

How is the reference type value related to the this value in the function context? -- In the most important sense. This association process is the core of this article. The general rules for determining the value of this in a function context are as follows:

In a function context, this is provided by the caller and determined by the method of calling the function. If the left side of the brackets () is the reference type value, this is set to the base object of the reference type value ), in other cases (any other attribute that is different from the reference type), the value is null. However, the actual value of this is null, because when the value of this is null, its value is implicitly converted to a global object. Note: In ECMAScript 5th, the value is undefined instead of being converted to a global variable.

Let's take a look at the performance in this example:
Copy codeThe Code is as follows:
Function foo (){
Return this;
}

Foo (); // global

We can see a reference type value on the left side of the call bracket (because foo is a identifier ).
Copy codeThe Code is as follows:
Var fooReference = {
Base: global,
PropertyName: 'foo'
};

Correspondingly, this is also set as a base object of the reference type. Global object.

Similarly, use the property accessors:
Copy codeThe Code is as follows:
Var foo = {
Bar: function (){
Return this;
}
};

Foo. bar (); // foo

We have a reference type again. Its base is a foo object, which is used as this when the function bar is activated.
Copy codeThe Code is as follows:
Var fooBarReference = {
Base: foo,
PropertyName: 'bar'
};

However, to activate the same function in another form, we get other this values.
Copy codeThe Code is as follows:
Var test = foo. bar;
Test (); // global

Because test is used as the identifier, other values of the reference type are generated, and its base (Global Object) is used as the this value.
Copy codeThe Code is as follows:
Var testReference = {
Base: global,
PropertyName: 'test'
};

Now, we can clearly tell you why activating the same function in different forms of expressions has different this values. The answer lies in the different intermediate values of the Reference type Reference.
Copy codeThe Code is as follows:
Function foo (){
Alert (this );
}

Foo (); // global, because

Var fooReference = {
Base: global,
PropertyName: 'foo'
};

Alert (foo = foo. prototype. constructor); // true

// Another call expression

Foo. prototype. constructor (); // foo. prototype, because

Var fooPrototypeConstructorReference = {
Base: foo. prototype,
PropertyName: 'constructor'
};

Another typical example of dynamically determining the value of this by calling:
Copy codeThe Code is as follows:
Function foo (){
Alert (this. bar );
}

Var x = {bar: 10 };
Var y = {bar: 20 };

X. test = foo;
Y. test = foo;

X. test (); // 10
Y. test (); // 20

Function call and non-reference type
Therefore, as we have already pointed out, when the left side of the call bracket is not a reference type but another type, this value is automatically set to null and the result is a global object.

Let's think about this expression:
Copy codeThe Code is as follows:
(Function (){
Alert (this); // null => global
})();

In this example, we have a function object, but it is not a reference type object (it is neither a identifier nor an attribute accessor). Correspondingly, this value is finally set as a global object.

More complex examples:
Copy codeThe Code is as follows:
Var foo = {
Bar: function (){
Alert (this );
}
};

Foo. bar (); // Reference, OK => foo
(Foo. bar) (); // Reference, OK => foo

(Foo. bar = foo. bar) (); // global?
(False | foo. bar) (); // global?
(Foo. bar, foo. bar) (); // global?

Why is there an attribute accesser whose median value should be a value of the reference type? In some calls, the value of this is not a base object, but a global object?

The problem lies in the following three calls. After a certain operation is applied, the value on the left of the call bracket is not of the reference type.

The first example is obvious-the obvious reference type. The result is that this is the base object, that is, foo.
In the second example, the group operator is not applicable. Think about the method mentioned above to obtain the true value of an object from the reference type, such as GetValue. Correspondingly, in the return of group operations, we still get a reference type. This is why this value is set as the base object again, that is, foo.
In the third example, unlike the group operator, the value assignment operator calls the GetValue method. The returned result is a function object (but not a reference type), which means that this is set to null and the result is a global object.
The fourth and fifth are the same-the comma operator and the logical operator (OR) Call the GetValue method. Correspondingly, we get the function without referencing it. And set it to global again.
The reference type and this are null.
One case is that when the call expression limits the reference type value on the left of the call bracket, although this is set to null, the result is converted to global by diet. This situation occurs when the base object of the reference type value is an active object.

In the following example, the internal function is called by the parent function, so we can see the special situation mentioned above. As we know in Chapter 12th, local variables, internal functions, and form parameters are stored in the activation object of a given function.
Copy codeThe Code is as follows:
Function foo (){
Function bar (){
Alert (this); // global
}
Bar (); // the same as AO. bar ()
}

The activity object is always returned as this, and the value is null -- (that is, the AO. bar () of the pseudo code is equivalent to null. bar ()). Here we will go back to the example described above and set this as a global object.

Except for one case: If the with object contains a function name attribute, call the function in the internal block of the with statement. The With statement is added to the frontend of the object scope, that is, before the activity object. Correspondingly, there is a reference type (via the identifier or attribute accessors). Its base object is no longer an active object, but an object of the with statement. By the way, it is not only related to internal functions, but also to global functions, because with objects are more advanced than the objects (global objects or an active object) in the scope chain) it must be on the front.
Copy codeThe Code is as follows:
Var x = 10;

With ({

Foo: function (){
Alert (this. x );
},
X: 20

}){

Foo (); // 20

}

// Because

Var fooReference = {
Base: _ withObject,
PropertyName: 'foo'
};

The same situation occurs in the actual parameters of the catch statement: In this case, the catch object is added to the frontend of the scope, that is, before the active object or global object. However, this particular behavior was identified as a bug in the ECMA-262-3, which was fixed in the new ECMA-262-5. In this way, this points to a global object in a specific activity object. Instead of catch objects.
Copy codeThe Code is as follows:
Try {
Throw function (){
Alert (this );
};
} Catch (e ){
E (); // The standard of ES3 is _ catchObject, and the standard of ES5 is global.
}

// On idea

Var eReference = {
Base: _ catchObject,
PropertyName: 'E'
};

// ES5 has fixed this bug in the new logo,
// This is the global object.
Var eReference = {
Base: global,
PropertyName: 'E'
};

The same situation occurs in the recursive call of the name function (for more information about the function, see Chapter 15th Functions. In the first call of a function, the base object is a parent activity object (or global object). In recursive calls, the base object should be a specific object that stores the optional name of a function expression. However, in this case, this always points to a global object.
Copy codeThe Code is as follows:
(Function foo (bar ){

Alert (this );

! Bar & foo (1); // "shocould" be special object, but always (correct) global

}) (); // Global

This in the function called by the constructor
Another case related to this value is in the context of the function, which is a constructor call.
Copy codeThe Code is as follows:
Function (){
Alert (this); // create a new property under the "a" Object
This. x = 10;
}

Var a = new ();
Alert (a. x); // 10

In this example, the new operator calls the [[Construct] method inside the "A" function, and then calls the internal [[Call] method after the object is created. All the same function "A" sets the value of this as the newly created object.

Manually set this in function call
The two methods defined in the function prototype (so all functions can access it) allow you to manually set the this value for function calls. They are. apply and. call methods. They use the first accepted parameter as the value of this, which is used in the scope of the call. The difference between the two methods is very small. For. apply, the second parameter must be an array (or an object similar to an array, such as arguments, in turn,. call can accept any parameter. The required parameters of the two methods are the first -- this.

For example:
Copy codeThe Code is as follows:
Var B = 10;

Function a (c ){
Alert (this. B );
Alert (c );
}

A (20); // this = global, this. B = 10, c = 20

A. call ({B: 20}, 30); // this = {B: 20}, this. B = 20, c = 30
A. apply ({B: 30}, [40]) // this = {B: 30}, this. B = 30, c = 40

Conclusion
In this article, we discuss the features of the this keyword in ECMAScript (compared with C ++ and Java, they are indeed characteristic ). I hope this article will help you understand exactly how the this keyword works in ECMAScript. Similarly, I am happy to return to your question in the comments.

Other references

  • 10.1.7-This
  • 11.1.1-The this keyword
  • 11.2.2-The new operator
  • 11.2.3-Function CILS

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.