Tips, working principles, and precautions for using this keyword in JavaScript

Source: Internet
Author: User

This can be understood based on the location of this:

1. In a function: this is usually an implicit parameter.

2. Out-of-function (top-level scope): in the browser, this refers to a global object, and in Node. js, it refers to the module Export (exports ).

3. String passed to eval (): If eval () is called directly, this indicates the current object; If eval () is called indirectly, this is a global object.

We have tested these categories:
1. In the function, this

Functions can basically represent all the callable structures in JS, so this is also the most common use case, and functions can be divided into the following three roles:

Real Function
Constructor
Method

1.1 In the real function, this

In a real function, the value of this depends on the context mode.

Sloppy mode: this indicates a Global Object (window in the browser ).

Copy codeThe Code is as follows:
Function sloppyFunc (){
Console. log (this = window); // true
}
SloppyFunc ();

Strict mode: the value of this is undefined.

Copy codeThe Code is as follows:
Function strictFunc (){
'Use strict ';
Console. log (this = undefined); // true
}
StrictFunc ();

This is an implicit parameter of the function, so its value is always the same. However, you can use the call () or apply () method to display and define the value of this.

Copy codeThe Code is as follows:
Function func (arg1, arg2 ){
Console. log (this); // 1
Console. log (arg1); // 2
Console. log (arg2); // 3
}
Func. call (1, 2, 3); // (this, arg1, arg2)
Func. apply (1, [2, 3]); // (this, arrayWithArgs)

1.2 this In the constructor

You can use a function as a constructor through new. The new operation creates a new object and passes the object to the constructor through this.

Copy codeThe Code is as follows:
Var savedThis;
Function Constr (){
SavedThis = this;
}
Var inst = new Constr ();
Console. log (savedThis === inst); // true

The implementation principle of the new operation in JS is roughly as follows ):

Copy codeThe Code is as follows:
Function newOperator (Constr, arrayWithArgs ){
Var thisValue = Object. create (Constr. prototype );
Constr. apply (thisValue, arrayWithArgs );
Return thisValue;
}

1.3 this in the Method

In the method, this is more inclined to the traditional object-oriented language: the receiver that this points to, that is, the object that contains this method.

Copy codeThe Code is as follows:
Var obj = {
Method: function (){
Console. log (this = obj); // true
}
}
Obj. method ();

2. this in the scope

In the browser, the scope is the global scope, and this refers to the Global Object (like window ):

Copy codeThe Code is as follows:
<Script>
Console. log (this = window); // true
</Script>

In Node. js, you usually execute functions in the module. Therefore, the top-level scope is a very special module scope ):

Copy codeThe Code is as follows:
// 'Global' (not 'window') refers to global object:
Console. log (Math === global. Math); // true

// 'This' doesn' t refer to the global object:
Console. log (this! = Global); // true
// 'I' refers to a module's exports:
Console. log (this = module. exports); // true

3. this in eval ()

Eval () can be called directly (by calling this function name 'eval') or indirectly (by other means, such as call. For more details, see here.

Copy codeThe Code is as follows:
// Real functions
Function sloppyFunc (){
Console. log (eval ('eas') === window); // true
}
SloppyFunc ();

Function strictFunc (){
'Use strict ';
Console. log (eval ('eas') === undefined); // true
}
StrictFunc ();

// Constructors
Var savedThis;
Function Constr (){
SavedThis = eval ('eas ');
}
Var inst = new Constr ();
Console. log (savedThis === inst); // true

// Methods
Var obj = {
Method: function (){
Console. log (eval ('eas') === obj); // true
}
}
Obj. method ();

4. this-related traps

Be careful with the three traps related to this described below. In the following example, Strict mode can improve code security. Because the value of this in the real function is undefined, you will receive a warning when a problem occurs.

4.1 forget to use new

If you are not using new to call the constructor, you are actually using a real function. Therefore, this is not your expected value. In Sloppy mode, this points to the window and you will create a global variable:

Copy codeThe Code is as follows:
Function Point (x, y ){
This. x = x;
This. y = y;
}
Var p = Point (7, 5); // we forgot new!
Console. log (p = undefined); // true

// Global variables have been created:
Console. log (x); // 7
Console. log (y); // 5

However, if the strict mode is used, you still get a warning (this = undefined ):

Copy codeThe Code is as follows:
Function Point (x, y ){
'Use strict ';
This. x = x;
This. y = y;
}
Var p = Point (7, 5 );
// TypeError: Cannot set property 'X' of undefined

4.2 improper use

If you directly obtain the value of a method (not call it), you just use this method as a function. If you want to pass a method as a parameter to a function or call a method, you are likely to do so. This is the case with setTimeout () and event handlers. I will use the calender () method to simulate this scenario:

Copy codeThe Code is as follows:
/** Similar to setTimeout () and setImmediate ()*/
Function calender (func ){
Func ();
}

If you call a method as a function in Sloppy mode, * this * points to a global object, so all created later are global variables.

Copy codeThe Code is as follows:
Var counter = {
Count: 0,
// Sloppy-mode method
Inc: function (){
This. count ++;
}
}
Calender (counter. inc );

// Didn't work:
Console. log (counter. count); // 0

// Instead, a global variable has been created
// (NaN is result of applying ++ to undefined ):
Console. log (count); // NaN

If you do this in Strict mode, this is undefined. You still cannot get the desired result, but at least you will get a warning:

Copy codeThe Code is as follows:
Var counter = {
Count: 0,
// Strict-mode method
Inc: function (){
'Use strict ';
This. count ++;
}
}
Calender (counter. inc );

// TypeError: Cannot read property 'Count' of undefined
Console. log (counter. count );

To get the expected results, you can use bind ():

Copy codeThe Code is as follows:
Var counter = {
Count: 0,
Inc: function (){
This. count ++;
}
}
Calender (counter. inc. bind (counter ));
// It worked!
Console. log (counter. count); // 1

Bind () creates a function that can always set this value to counter.

4.3 hide this

When you use a function in a method, you often ignore that the function has its own this. This is different from the method, so you cannot mix the two. For details, see the following code:

Copy codeThe Code is as follows:
Var obj = {
Name: 'Jane ',
Friends: ['tarza', 'cheeta '],
Loop: function (){
'Use strict ';
This. friends. forEach (
Function (friend ){
Console. log (this. name + 'done' + friend );
}
);
}
};
Obj. loop ();
// TypeError: Cannot read property 'name' of undefined

In the above example, this. name in the function cannot be used, because the value of this in the function is undefined, which is different from this in the method loop. The following three ideas are provided to solve this problem:

1. that = this: assign this value to a variable, so that this is expressed explicitly (except that, self is also a very common variable name used to store this), and then use that variable:

Copy codeThe Code is as follows:
Loop: function (){
'Use strict ';
Var that = this;
This. friends. forEach (function (friend ){
Console. log (that. name + 'done' + friend );
});
}

2. bind (). Use bind () to create a function. this function always contains the value you want to pass (in the following example, this of the method ):

Copy codeThe Code is as follows:
Loop: function (){
'Use strict ';
This. friends. forEach (function (friend ){
Console. log (this. name + 'done' + friend );
}. Bind (this ));
}

3. Use the second parameter of forEach. The second parameter of forEach will be passed into the callback function and used as this of the callback function.

Copy codeThe Code is as follows:
Loop: function (){
'Use strict ';
This. friends. forEach (function (friend ){
Console. log (this. name + 'done' + friend );
}, This );
}

5. Best practices

In theory, I think the real function does not belong to its own this, and the above solution also follows this idea. ECMAScript 6 uses the arrow function to achieve this effect. The arrow function does not have its own this function. In such a function, you can use this without worrying about Implicit existence.

Copy codeThe Code is as follows:
Loop: function (){
'Use strict ';
// The parameter of forEach () is an arrow function
This. friends. forEach (friend => {
// 'Eas' is loop's 'eas'
Console. log (this. name + 'done' + friend );
});
}

I don't like some APIs that use this as an additional parameter for real functions:

Copy codeThe Code is as follows:
BeforeEach (function (){
This. addMatchers ({
ToBeInRange: function (start, end ){
...
}
});
});

When a implicit parameter is written as an explicit parameter, the code will be better understood, and the requirements of the arrow function are also very consistent:

Copy codeThe Code is as follows:
BeforeEach (api => {
Api. addMatchers ({
ToBeInRange (start, end ){
...
}
});
});

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.