The meaning of the “this” operator in JavaScript

Introduction

js this

Developers use one of these two mechanisms:

  • lexical range of visibility
  • “this mechanism”

The mechanism using the “this” keyword provides an elegant way to implicitly “pass” a reference to a particular object, resulting in a cleaner design and easier code reuse. Developers who avoid using this mechanism mostly do so because they don’t understand the principles of how that mechanism works.

“This” is not a variable but a special programming language word (operator) and represents a link that points to some reference (object). It is activated, i.e. gains meaning only at the moment when the function that contains it is called (invoke).

It does not depend on where the function is declared, but solely on where and how the function is called!

Rules for determining the meaning of “this”

The whole process of determining the meaning is based on recognizing “who” and how it calls the function containing “this”. The sequence of actions is as follows:

  1. First it is checked whether the constructor function is called with operator new(). If it is called in this way, then the value “this” is explained under the point a) Calling the function with the operator “new” but if it is not called in this way, then it is done…
  2. … control whether the function is called with the help of call(), apply() (or bind) methods. If it is called in this way, then the value of “this” is explained under point b) Calling with call(), apply() or bind(), but if it is not called in this way, then it is done …
  3. …check if the function is called as a method of the object. If it is called in this way, then the value “this” is explained under the point c) Calling the method of the object, but if it is not called in this way, then it is…
  4. default linking, which is explained under d) Default linking

If by any chance several different rules are used, priority is applied according to the order from the previously described procedure.

a) Calling the function with the “new” operator

After calling the constructor function with the new operator, this inside the constructor function points to an object instance.

b) Calling with call(), apply() or bind()

this bind apply call

In JavaScript, functions are objects, in the language itself there are predefined methods for them and they can be used on any function. The built-in methods that can change the object pointed to by the this operator are: apply(), call() and bind(). The main difference between the bind() method and the apply()/call() method is that the apply()/call() methods immediately call (eng. invoke) the function, while the bind() method does not, so it is necessary to additionally call the function. In the following example it isshown “binding” this in a function defined outside the object using bind(), to the desired object.

In the call() and apply() methods, the first argument defines which object this will point to, while the other arguments pass the parameters needed by the basic function. The only difference between the apply() and call() methods is the way the method accepts the arguments passed to the base function. The call() method adds other arguments with a comma, while the apply() method adds other elements as an array of elements.

TIP:
To make it easier to remember in which form each method accepts arguments, use the first letters of the method:
Apply <=> Array or Call <=> Comma.

c) Calling the object method

When a function is inside an object, then when calling the object’s method, the this keyword points to that object (which is the “owner” of the method).

Since this points to the person object, we can use it from the method to call the properties of the object:

Example

In the previous example, the foo() function is not directly owned by the “externalObject” object, but the object property has an external reference to that function. For determining the objects pointed to by the operator this, the place of calling the function that engages this is important, so in this case, since the function is called from the object “externalObject”, it behaves like a method of the object, so this points to the object!

Example

The following example shows that only the “closest” (“last”) object in the expression for calling the function is important, i.e. that the this operator points to it.

d) Default behavior

The default behavior is used when no other rule applies. When this rule applies this points to the global object (window).

Example

In the following example, the function foo() is called from the global context and not as an object method, so this points to a global object:

NOTE:
Most often, the programmer does not want the this special word to point to a global object, but if the default linking rule is applied anyway (most often due to an inadvertent programming error), the compiler will not throw any error! Therefore, it is recommended to turn on strict mode because in that case the compiler throws an “undefined” error for every reference to a global object, so the programmer can spot the error in time.
Example

So the same example as the previous one but with strict mode on it returns undefined

Problems with “this” and their solutions

Through the following examples, I will try to explain the cases when the behavior of the word this is confusing, ie. when this does not behave as we expect at first sight. From the point of view of “this”, it only matters from where the function containing the this operator is called.

Problematic cases

a) “This” inside the closure

Problem occurring with clousure‘s function is that although they are inside the object, they do not have access to the object through their this operator (because it points to a global object). The Closure function is called by another function and not an object, so the “default rule” is used.

In this example, the method person.fullName() is called, which calls the function mergeName(). Since the function concatenateNames() is not called from the object (it was called by another function) the “default rule” is used. Therefore, calling the fullName() method returns undefined, because this points to the global object window, and the global object window does not have window.name and window.surname properties.

Solution

The best solution to this problem is with the help of the bind() method, which binds “this” function mergeName() to “this” function fullName(). After that, since this of the fullName() method points to the “person” object, so our this internal function will also point to the “person” object.

In addition to this method, we can solve the problem using the “self=this” mechanism or the arrow function because the “parent” function has access to the object (through its “this”).

b) “This” inside setTimeout()

The setTimeout() function calls the callback function after some time interval (which means the function was called from another function, not an object). Therefore, the “default behavior” applies, so this points to a global object. In the following example, this points to a global object:

This constructor can be written differently by extracting the callback function as a new property of the prototype object, and then we can call it with this.callback:

This problem is solved by using the bind() method. It is necessary to bind “this” inside the callback function to each newly created object. Therefore, the parameter of the bind() method should be the object that we want “this” to point to, which in this case is again “this” (after using the “new” operator, “this” points to the newly created object)

c) “This” in the so-called “extracted method”

A method is just a property of an object that has a reference to some function. When we assign an object method to a variable, we have assigned a function reference to the variable. Therefore, it should be understood that by calling that variable we are not calling a method of the object but an ordinary function.

Example

The preceding example from the this viewpoint looks like this:

From the attachment it can be seen that the function displayFullName() is called, not the method of the object. Therefore, the “default rule” is used when this points to a global window object that has no window.name and window.surname properties and returns undefined, undefined.

Problem solution

This problem is solved with the bind() method, with which we will explicitly bind this from the function to the “person” object, after which it no longer matters from where the function is called.

d) “This” inside the Event handler

This inside the “inline” event handler

One ofthe biggest drawback of this outdated way of registering events is that this points to a global object.

“This” within the traditional event handler and the W3C model

In traditional event registration, this indicates the element that was the trigger for the event.

“This” within the W3C event handler model

In the W3C model with addEventListener() this indicates the element that was the trigger for the event.

Troubleshooting Procedures

If “this” doesn’t point to what we want, there are ways we can change the meaning of the “this” keyword.

a) bind(), call(), apply()

One way to predefine the meaning of “this” is to use one of the methods: bind(), call(), apply(). All three methods, through an argument, define an object to which this from the function should be “attached”. Therefore, when calling the method, it is enough to add one of the mentioned methods:

b) Arrow function

With the new version of JavaScript ECMAScript 6 comes a new way of writing the arrow function. Arrow function instead of applying one of the 4 standard rules for binding this, it completely bypasses the standard mechanism and binds this to the surrounding scope of visibility (lexical scope of visibility). When calling these functions, this inherits the meaning of this from the surrounding function. Simplified this arrow function equates to what this would point to from the external function surrounding the arrow function (it has a built-in engine that practically replaces the known mechanism: “self=this”). When using the arrow function it doesn’t matter how and where the function is called, only what this from the external function points to.

The meaning given to the this operator inside the arrow function cannot be changed later! So it cannot be overridden with the predefined bind(), apply() or call() methods or even with the “new” operator.

Example (closure)

The already mentioned problem from the transition part can also be solved using the arrow function:

Solution

Since the arrow function is used, it inherits the meaning of this from the surrounding function that “wraps” the arrow function. In this case, the surrounding function is fullName(), so this inside the arrow function will point to the same as the fullName() function, i.e. this will point to the object “person”.

c) “self=this” mechanism

This mechanism actually does not use the this operator, but instead bypasses its application. The problem that occurs with closure functions is that although they are inside the object, they do not have access to the object through their this operator (because it points to a global object). However, its “parent” function has access to the object, through its “this” operator, and we will use that to solve the problem.
If we store a reference to the object (pointed to by the outer function’s “this”) within a new variable (e.g.“self”), we will allow the inner function (closure) to access the objectvia that new variable “self”.