The this
problem is one of the most complex problems in JavaScript, and even experienced programmers can inadvertently fall into the this
keyword pit. Whenever a function is defined, this
is automatically defined inside the function (even if the this
keyword is not used inside the function).
Function call location
Before understanding this
, let’s understand function call location. The call position of a function is where the function is called, not where it is declared. In order to understand call location, it is important to analyze a function’s call stack , which is a chain of function executions, to understand the call stack and call location by following a few examples.
We define three functions f1
, f2
and f3
, execute f1()
, because f2
is called inside f1
, and f3
is called inside f2
, so the program will execute f2()
and f3()
one after another, the call stack is f1 when executing f1, when executing f2
, the call stack is f1
–> f2
, when executing f3
, the call stack is f1 --> f2 --> f3
, so the call stack is similar to a single chain table, from the head of the table to the end of the table in order of execution.
Some debugging tools have a special call stack panel that shows the call stack of the current program execution. In Google Chrome, you can press F12
to open Developer Tools and switch to the Sources
page, you can see the call stack
panel, which will show the call stack when the program is executed.
Binding rules
Below, I have summarized four binding rules for this
. Before applying the following rules, you need to analyze the call stack to find where the function is called, and then judge to apply one of the four rules below.
Default Binding
This is the default rule for this
binding, which is used when no other rule can be applied.
A variable declared in a global scope in JavaScript is a property of the same name of the global object. In the browser environment, this global object is window
, so var a = 2
is equivalent to window.a = 2
.
When using default binding, this
is bound to the global object. In the above example, when the function f()
is executed, this
is default bound to the global object, i.e., this
is pointing to the global object, so the output is 2.
Note that when the program is declared "use strict"
, the global object cannot be used for default binding.
Note: Try to use strict patterns in your code, non-strict patterns tend to write code that is difficult to maintain. And don’t use a mix of strict and non-strict patterns.
Implicit binding
When a function is executed, it belongs to some object Object, then this
is bound to that object at that time.
Although the function f
is defined in the global scope, it is added to obj as a reference, and when obj.f()
is executed, f
‘belongs’ to obj
, so the output is 3.
Change the above example a bit.
At this point, the output is 2. Why? Because strictly speaking functions do not belong to any one object, the obj.f
and f
in the above example are just a reference to a function, so f
and obj.f
are not directly related, just the same function referenced, so the execution of f()
, at this time the execution environment in the global scope, will automatically apply the default binding rules to bind this
to the global object. The second example, a more common this binding problem, is called implicit loss of this .
The problem of implicit loss is often encountered in callback functions.
When executing f2(obj.f)
, you actually try to assign f1
to the argument f
of f2
, which is actually just a reference to the function, so the result is "global"
.
Show bindings
The bind this value can be displayed with the call
, apply
and bind
functions.
With the call
method, the display specifies that this is bound to the obj
object, and the output is 2. Multiple arguments can be passed to call
, with the first argument specifying the this
binding object and the subsequent arguments specifying the arguments needed to execute the function.
The apply
method is similar to call
, except that the call
method takes a list of arguments, while the apply
method takes an array of multiple arguments.
The bind
method creates a new function, and when bind
is called, this
of this new function is specified as the first argument of bind
, and the rest of the arguments will be used as arguments of the new function for the call.
|
|
new binding
If you haven’t worked in a language other than JavaScript, you’ll probably rarely use the new
keyword, because there are no actual classes
in JavaScript (classes in Es6 are actually functions at the bottom). newoperator, they do not belong to a class, nor do they instantiate a class, they are just ordinary functions that are called by the
new` operator.
Calling a function (constructor) with new
will automatically perform the following steps.
- Create a new empty object as an instance of the object to be returned.
- Prototype the empty object to the function’s
prototype
property. - Bind the empty object to the
this
keyword inside the function. - Execute the code inside the function (usually by assigning a value to the this attribute and initializing the object).
The third step above, is the new binding.
Complete steps
After describing the four binding rules, the next step is to describe the complete steps to determine the priority of each method.
- new binding, if the function is called in
new
, thenthis
is bound to the newly created object. - display binding, if the function is called in
call
,apply
orbind
, thenthis
binds to the specified object. - implicit binding, if the function is called in some context object, if yes, then
this
is bound to that context object. 4. - If none of the above, the default binding is used, which is
undefined
in strict mode and the global object in non-strict mode.
Exceptions
There are always exceptions to everything, and here is one of the more common exceptions - the arrow function =>
.
Instead of using the four binding rules of this
, arrow functions determine who to bind this
to based on the outer (function or global) scope.
Why is the this of the above myMethod()
execution a global object? Because the this of an arrow function inherits from its outer (function or global) scope.
Continue with an example.
|
|