To understand this according to its location, the situation can be roughly divided into three types:
1. In functions: this is usually an implicit parameter.
2. Outside the function (in the top-level scope): In the browser, this refers to the global object; in Node.js, it refers to the exports of the module.
3. The string passed to eval(): If eval() is called directly, this refers to the current object; if eval() is called indirectly, this refers to the global object.
We have conducted corresponding tests for these categories:
1. this in the function
Functions can basically represent all callable structures in JS, so this is the most common scenario for using this, and functions can be divided into the following three roles:
Real function
Constructor
Method
1.1 this
in real functionsIn real functions, the value of this is a pattern that depends on the context in which it is found.
Sloppy mode: this refers to the global object (window in the browser).
Strict mode: the value of this is undefined.
this is an implicit parameter of the function, so its value is always the same. However, you can explicitly define the value of this by using the call() or apply() method.
1.2 this
in the constructorYou can use new to use a function as a constructor. The new operation creates a new object and passes this object into the constructor through this.
The implementation principle of new operation in JS is roughly as shown in the following code (please see here for a more accurate implementation, this implementation is also more complicated):
1.3 this
in the methodThe usage of this in methods is more inclined to traditional object-oriented languages: the receiver pointed to by this is the object that contains this method.
2. this in scope
In the browser, the scope is the global scope, and this refers to the global object (just like window):
In Node.js, you usually execute functions in modules. Therefore, the top-level scope is a very special module scope:
3. this in eval()
eval() can be called directly (by calling the function name 'eval') or indirectly (called by other means, such as call()). For more details, see here.
4. Traps related to this
You should be careful of the 3 traps related to this that will be introduced below. It should be noted that in the following examples, using Strict mode can improve the security of the code. Since in real functions, the value of this is undefined, you will get a warning when something goes wrong.
4.1 Forgot to use new
If you are not using new to call the constructor, then you are actually using a real function. Therefore this will not be the value you expected. In Sloppy mode, this points to window and you will create global variables:
However, if you are using strict mode, you will still get a warning (this===undefined):
4.2 Improper use of methods
If you directly get the value of a method (not call it), you are using the method as a function. You'll probably do this when you want to pass a method as a parameter into a function or a calling method. This is the case with setTimeout() and registered event handlers. I will use the callIt() method to simulate this scenario:
If you call a method as a function in Sloppy mode, *this* points to the global object, so all subsequent creations will be global variables.
If you do this in Strict mode, this is undefined, and you still won’t get the desired result, but at least you will get a warning:
To get the expected results, you can use bind():
bind() creates another function that always sets the value of this to counter.
4.3 Hide this
When you use a function in a method, you often forget that the function has its own this. This this is different from the method, so you cannot mix the two this together. For details, please see the following code:
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.
5. Best Practices
Theoretically, I think real functions do not have their own this, and the above solution is also based on this idea. ECMAScript 6 uses arrow functions to achieve this effect. Arrow functions are functions that do not have their own this. In such a function, you can use this casually, and you don't have to worry about whether it exists implicitly.
I don’t like that some APIs treat this as an additional parameter of the real function: