Deep understanding of the JavaScript series (a) this? Yes,this!_javascript Tips

Source: Internet
Author: User
Tags function prototype logical operators
Introduced
In this article, we will discuss more details that are directly related to the execution context. The subject of the discussion is the this keyword. Practice has proved that this topic is difficult, and the determination of this in different execution contexts often has problems.

Many programmers are accustomed to the view that in the programming language, the This keyword is closely related to Object-oriented program development, and it completely points to the newly created object by the constructor. This is done in the ECMAScript specification, but as we'll see, in ECMAScript, this is not limited to pointing to newly created objects.

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

Russian original: Dmitry A. Soshnikov
Fixed: Zeroglif
Released: 2009-06-28;
Updated: 2010-03-07
http://dmitrysoshnikov.com/ecmascript/ru-chapter-3-this/

Most of the contents of this article refer to: http://www.denisdeng.com/?p=900
Part of the sentence reference: Justin's Chinese translation
Copy Code
Let's find out in more detail what this is in ECMAScript.

Defined
This is an attribute in the execution context:
Copy Code code as follows:

Activeexecutioncontext = {
VO: {...},
This:thisvalue
};

Here Vo is the variable object we discussed in the previous chapter.

This is directly related to the type of executable code in the context, the this value is determined when the context is entered, and is persisted during the context run.

Now let's look at these cases in more detail:

This in the global Code
Everything is simple here. In global code, this is always the global object itself, so it is possible to refer to it indirectly.
Copy Code code as follows:

Show properties that define global objects
THIS.A = 10; GLOBAL.A = 10
alert (a); 10

By assigning a value to an unsigned Fu Yin type
b = 20;
alert (this.b); 20

is also implicitly declared through a variable declaration.
Because the global context's variable object is the global object itself
var C = 30;
alert (THIS.C); 30

This in the function code
It is interesting to use this in the function code, which is difficult and can cause a lot of problems.

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

As we mentioned above, this is determined when entering the context, and in a function code, the value is completely different at each time.

In any case, the this value is invariant at the time the code is run, that is, because it is not a variable, it is not possible to assign a new value to it (instead, in the Python programming language, it is explicitly defined as the object itself and can be changed during runtime).
Copy Code code 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 it doesn't go wrong, it should be 10, not 20.

}

};

When you enter 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 invoked

Foo.test (); False, 10

Then, there are several factors that affect the change of this value in the function code:

First, in the usual function call, this is provided by the caller who activated the context code, that is, the parent context of the calling function. This depends on how the function is invoked.

In order to determine the this value accurately in any case, it is necessary to understand and remember this important point. It is the way the function is invoked that affects the this value in the context of the invocation, and nothing else (we can see in some articles, even in books about JavaScript, that 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 a method of an object, this will always point to this object. – This is absolutely incorrect "). Continuing with our topic, we can see that even normal global functions are activated in different forms of invocation, and these different invocation methods result in different this values.
Copy Code code as follows:

function foo () {
alert (this);
}

Foo (); Global

Alert (foo = = Foo.prototype.constructor); True

But the different invocation expressions of the same function, this is different

Foo.prototype.constructor (); Foo.prototype

It is possible to invoke a function as some object-defined method, but this will not be set to this object.
Copy Code code as follows:

var foo = {
Bar:function () {
alert (this);
Alert (This = = = foo);
}
};

Foo.bar (); Foo, True

var examplefunc = Foo.bar;

Alert (Examplefunc = = Foo.bar); True

Again, the different invocation expressions of the same function, this is different

Examplefunc (); Global, False

So how does calling a function affect the this value? In order to fully understand the determination of this value, it is necessary to analyze one of its internal types in detail-reference type (Reference type).

Reference type (Reference type)
Using pseudocode we can represent the value of a reference type as an object with two properties--base (that is, the object that owns the attribute), and the PropertyName in base.
Copy Code code as follows:

var Valueofreferencetype = {
Base: <base Object>
PropertyName: <property name>
};

There are only two types of values for a reference type:

When we deal with a marked characters
or a property accessor
The process of the identifier is discussed in detail in the next article, where we only need to know that in the return value of the algorithm, it is always a reference type value (which is important for this).

Identifiers are variable names, function names, function parameter names, and unrecognized property names in global objects. For example, the value of the following identifier:
Copy Code code as follows:

var foo = 10;
function bar () {}

In the intermediate results of the operation, the reference type corresponds to the following values:
Copy Code code as follows:

var fooreference = {
Base:global,
PropertyName: ' foo '
};

var barreference = {
Base:global,
PropertyName: ' Bar '
};

In order to get an object's true value from a reference type, the GetValue method in pseudocode can be described as follows:
Copy Code code 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 value of the object property, including the attribute analysis inherited from the prototype chain.
Copy Code code as follows:

GetValue (fooreference); 10
GetValue (barreference); Function Object "Bar"

Property accessors should be familiar. It has two variants: the point (.) syntax (at which time the property name is the correct identifier and is known beforehand), or the parenthesis syntax ([]).
Copy Code code as follows:

Foo.bar ();
foo[' Bar '] ();

In the return value of the intermediate calculation, we have the value of the reference type.
Copy Code code as follows:

var foobarreference = {
Base:foo,
PropertyName: ' Bar '
};

GetValue (foobarreference); Function Object "Bar"

How does the value of a reference type relate to the this value in the function context? --in the most important sense. The associated process is at the heart of this article. The general rules for determining this value in a function context are as follows:

In the context of a function, this is provided by the caller and is determined by the way the function is invoked. If the left side of the call bracket () is a value of a reference type, this is set to the base object (base objects) that refers to the type value, and in other cases (any other property that differs from the reference type), this value is null. However, there is no actual case where this value is NULL, because its value is implicitly converted to the global object when the value of this is null. Note: In the 5th edition of ECMAScript, it is not forced to convert to a global variable, but to undefined.

Let's look at the performance in this example:
Copy Code code as follows:

function foo () {
return this;
}

Foo (); Global

We see a reference type value on the left side of the call bracket (because Foo is an identifier).
Copy Code code as follows:

var fooreference = {
Base:global,
PropertyName: ' foo '
};

Accordingly, this is also set to the base object of the reference type. is the global object.

Also, use the property accessor:
Copy Code code as follows:

var foo = {
Bar:function () {
return this;
}
};

Foo.bar (); Foo

We have a reference type again, base is the Foo object, which is used as this when function bar is activated.
Copy Code code as follows:

var foobarreference = {
Base:foo,
PropertyName: ' Bar '
};

However, to activate the same function in a different form, we get the other this value.
Copy Code code as follows:

var test = Foo.bar;
Test (); Global

Because test is the identifier, other values of the reference type are generated, and its base (global object) is used as the this value.
Copy Code code as follows:

var testreference = {
Base:global,
PropertyName: ' Test '
};

Now, we can clearly tell you why activating the same function in different forms is different from this value, and the answer lies in the different intermediate values of the reference type (type Reference).
Copy Code code as follows:

function foo () {
alert (this);
}

Foo (); Global, because

var fooreference = {
Base:global,
PropertyName: ' foo '
};

Alert (foo = = Foo.prototype.constructor); True

Another form of invocation expression

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

var fooprototypeconstructorreference = {
Base:foo.prototype,
PropertyName: ' Constructor '
};

Another classic example of dynamically determining this value by calling a method:
Copy Code code 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 calls and non-reference types
So, as we have already pointed out, when the call bracket's left side is not a reference type but another type, the value is automatically set to null and the result is a global object.

Let's think about this expression again:
Copy Code code as follows:

(function () {
alert (this); Null => Global
})();

In this example, we have a function object that is not a reference type object (it is not a identifier, nor is it a property accessor), and, accordingly, the this value is eventually set to the global object.

More complex examples:
Copy Code code 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 do we have a property accessor whose intermediate value should be the value of a reference type, and in some calls the this value we get is not a base object, but a global object?

The problem is that the next three calls, after applying a certain operation, are not in the reference type at the left of the call bracket.

The first example is obviously ——— obvious reference type, and as a result, this is the base object, that is, Foo.
In the second example, the group operator does not apply, and think about the method mentioned above that obtains the true value of an object from a reference type, such as GetValue. Accordingly, in the return of the group operation ——— we are still a reference type. This is why this value is again set to the base object, that is, Foo.
In the third example, unlike the group operators, the assignment operator invokes the GetValue method. The result returned is a function object (but not a reference type), which means that this setting is null and the result is a global object.
The fourth and fifth are the same--the comma and logical operators (or) call the GetValue method, and correspondingly, we lose the reference and get the function. and set to global again.
Reference type and this is null
There is a situation where the invocation expression qualifies the value of the reference type to the left of the call bracket, although this is set to NULL, but the result is converted to global by the diet. This occurs when the base object that refers to the type value is the active object.

In the following example, the intrinsic function is called by the parent function, and we can see the special case described above. As we know in chapter 12th, local variables, intrinsic functions, and formal parameters are stored in the activation object of the given function.
Copy Code code as follows:

function foo () {
function Bar () {
alert (this); Global
}
Bar (); The same as Ao.bar ()
}

The active 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 go back to the example described above, this is set as a global object.

In one case: if the With object contains a function Name property, the function is called in the inner block of the with statement. The WITH statement is added to the end of the scope of the object, in front of the active object. Correspondingly, there is a reference type (through the identifier or property accessor) whose base object is no longer the active object, but the object of the WITH statement. Incidentally, it is related not only to internal functions, but also to global functions, because the with object is ahead of the most front-end object in the scope chain (global object or an active object).
Copy Code code 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 appears in the actual parameters of the catch statement in the function call: In this case, the catch object is added to the front of the scope, that is, before the active object or global object. However, this particular behavior was identified as a bug in Ecma-262-3, which was fixed in the new version of Ecma-262-5. Thus, in a specific active object, this points to the global object. Rather than a Catch object.
Copy Code code as follows:

try {
Throw function () {
alert (this);
};
catch (e) {
E (); The ES3 standard is __catchobject, the ES5 standard is global.
}

On idea

var ereference = {
Base: __catchobject,
PropertyName: ' E '
};

ES5 has fix this bug in the new standard,
So this is the global object.
var ereference = {
Base:global,
PropertyName: ' E '
};

The same situation occurs in a recursive invocation of a named function (the function's more detailed reference to chapter 15th functions). In the first invocation of a function, the base object is a parent activity object (or Global object), and in a recursive invocation, the base object should be a specific object that stores the optional name of the function expression. However, in this case, this always points to the global object.
Copy Code code as follows:

(function foo (bar) {

alert (this);

!bar && foo (1); "Should" be special object, but always (correct) global

})(); Global

This in a function called by the constructor
Another case related to this value is in the context of the function, which is called by a constructor.
Copy Code code as follows:

function A () {
alert (this); Create a new property under the "a" object
This.x = 10;
}

var a = new A ();
alert (a.x); 10

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

manually set this in a function call
The two methods defined in the function prototype (so that all functions can access it) allow you to manually set the this value of the function call. They are. Apply and. Call methods. They use the first argument accepted as this value, this is used in the scope of the invocation. The difference between the two methods is very small, for. Apply, the second argument must be an array (or an array-like object, such as arguments, in turn,. Call can accept any argument. Two methods must have parameters that are the first--this.

For example:
Copy Code code as follows:

var B = 10;

function A (c) {
alert (this.b);
alert (c);
}

A (20); this = = Global, this.b = = 20

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

Conclusion
In this article, we discussed the features of the This keyword in ECMAScript (compared to C + + and Java, they are indeed characteristic). I hope this article will help you to understand exactly how the This keyword works in ECMAScript. Again, I'd be happy to return to your question in the comments.

Other Reference
    • 10.1.7–this
    • 11.1.1–the this keyword
    • 11.2.2–the new operator
    • 11.2.3–function calls

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.