What is written in this? Behind the scenes of JavaScript objects
- Transfer
JavaScript is a multi-paradigm language that supports object-oriented programming and dynamic method binding - a powerful concept that allows the structure of JavaScript code to change during program execution. This gives developers serious opportunities, it makes the language flexible, but you have to pay for everything. In this case, you have to pay with the clarity of the code. A significant contribution to this price is made by the keyword
Dynamic binding allows you to specify, during program execution, and not during compilation, the method that must be called when executing a certain command. In JavaScript, this mechanism is implemented using a keyword
Let's play one game. I call it "What is written in this?". Here is her first option - ES6 module code:
Before reading further, think about what will fall into the array
We will analyze this problem, starting with the first example. The construct
The command
It’s
With the help of the command,
You
Here is the second version of our game - the same task, but now based on classes. Here we use the syntax for declaring public class fields (at the moment, the proposal for this syntax is at the third stage of approval, it is available by default in Chrome, you can use it with the help
Before reading further, think about the code and write down your vision of what will fall into the array
Are you done?
Here, all method calls, except
Namely, here we work with class properties, which determines the behavior of this code.
The fact is that during the preparation of the code for execution, the values are written to the properties of the classes like this:
In other words, it turns out that the arrow function is declared inside the context of the constructor function. Since we are working with a class, the only way to instantiate it is to use a keyword
The most important tasks solved by the keyword
Have you completed the tasks outlined in this article? A good understanding of how the keyword behaves in JavaScript
Experiment with the sample code, and then try yourself again, and so on, until you can answer all the questions correctly. After you figure it out yourself, find someone ready to listen to you and tell him why the methods from the tasks return exactly what they return.
If all this seems to you more complicated than you expected, then know that you are not alone in this. I tested for knowledge of the features
That subsystem of the language, which, at the very beginning, looked like a dynamic search for methods that could be influenced by help
Apparently, it will be useful to note the main features of classes and arrow functions in terms of use
Also, keep in mind that you can do a lot in JavaScript without using it
Notwithstanding the foregoing, it should be noted that
this
, around the features of the behavior of which a lot has been collected that can confuse the programmer.Dynamic Method Binding
Dynamic binding allows you to specify, during program execution, and not during compilation, the method that must be called when executing a certain command. In JavaScript, this mechanism is implemented using a keyword
this
and a prototype chain. In particular, the specific value this
inside the method is determined at runtime, and the rules for determining this value change depending on how the method was declared. Let's play one game. I call it "What is written in this?". Here is her first option - ES6 module code:
const a = {
a: 'a'
};
const obj = {
getThis: () => this,
getThis2 () {
return this;
}
};
obj.getThis3 = obj.getThis.bind(obj);
obj.getThis4 = obj.getThis2.bind(obj);
const answers = [
obj.getThis(),
obj.getThis.call(a),
obj.getThis2(),
obj.getThis2.call(a),
obj.getThis3(),
obj.getThis3.call(a),
obj.getThis4(),
obj.getThis4.call(a)
];
Before reading further, think about what will fall into the array
answers
and write down the answers. After you do this - test yourself by listing the array answers
with console.log()
. Did you manage to correctly “decipher” the meaning this
in each of the cases? We will analyze this problem, starting with the first example. The construct
obj.getThis()
returns undefined
. Why? It is this
impossible to bind to the arrow function . Such functions are used this
from the surrounding lexical scope. The method is called in the ES6 module, in its lexical scope it this
will matter undefined
. For the same reason, it will undefined
return the call obj.getThis.call(a)
. The value this
when working with arrow functions cannot be reassigned even with .call()
or.bind()
. This value will always correspond this
from the lexical scope to which such functions are located. The command
obj.getThis2()
demonstrates how to work with this
using the usual methods of the object. If you this
did not bind to a similar method, and provided that this method is not an arrow function, that is, it supports binding this
, the keyword this
is bound to the object for which the method is called using the syntax of accessing the properties of the object through a point or with using square brackets. It’s
obj.getThis2.call(a)
already a little harder to deal with the design . The method call()
allows you to call a function with a given valuethis
, which is indicated as an optional argument. In other words, in this case it this
is taken from the parameter .call()
, as a result, the call obj.getThis2.call(a)
returns an object a
. With the help of the command,
obj.getThis3 = obj.getThis.bind(obj);
we are trying to bind to a this
method that is an arrow function. As we have already found out, this cannot be done. As a result, calls obj.getThis3()
and obj.getThis3.call(a)
returns undefined
. You
this
can bind methods that are ordinary functions, so obj.getThis4()
it returns as expected obj
. The call obj.getThis4.call(a)
returns obj
, and not, as one might expect a
. The fact is that, before calling this command, we already bound the this
team obj.getThis4 = obj.getThis2.bind(obj);
. As a result, when executedobj.getThis4.call(a)
takes into account the state of the method in which it was after completing the first binding.Using this in classes
Here is the second version of our game - the same task, but now based on classes. Here we use the syntax for declaring public class fields (at the moment, the proposal for this syntax is at the third stage of approval, it is available by default in Chrome, you can use it with the help
@babel/plugin-proposal-class-properties
).class Obj {
getThis = () => this
getThis2 () {
return this;
}
}
const obj2 = new Obj();
obj2.getThis3 = obj2.getThis.bind(obj2);
obj2.getThis4 = obj2.getThis2.bind(obj2);
const answers2 = [
obj2.getThis(),
obj2.getThis.call(a),
obj2.getThis2(),
obj2.getThis2.call(a),
obj2.getThis3(),
obj2.getThis3.call(a),
obj2.getThis4(),
obj2.getThis4.call(a)
];
Before reading further, think about the code and write down your vision of what will fall into the array
answers2
. Are you done?
Here, all method calls, except
obj2.getThis2.call(a)
, will return a reference to an instance of the object. The same call will return an object a
. Arrow functions are still taken this
from the lexical scope. The difference between this example and the previous one is the difference in the visibility areas from which it is taken this
. Namely, here we work with class properties, which determines the behavior of this code.
The fact is that during the preparation of the code for execution, the values are written to the properties of the classes like this:
class Obj {
constructor() {
this.getThis = () => this;
}
...
In other words, it turns out that the arrow function is declared inside the context of the constructor function. Since we are working with a class, the only way to instantiate it is to use a keyword
new
(if you forget about this keyword, an error message will be displayed). The most important tasks solved by the keyword
new
are to create a new instance of the object and to bind this
to the constructor. This feature, taking into account what we already talked about in the previous section, should help you understand what is happening.Summary
Have you completed the tasks outlined in this article? A good understanding of how the keyword behaves in JavaScript
this
will save you a lot of time when debugging, when looking for unobvious causes of obscure errors. If you answered some of the questions incorrectly, it means that it will be useful for you to practice. Experiment with the sample code, and then try yourself again, and so on, until you can answer all the questions correctly. After you figure it out yourself, find someone ready to listen to you and tell him why the methods from the tasks return exactly what they return.
If all this seems to you more complicated than you expected, then know that you are not alone in this. I tested for knowledge of the features
this
quite a few developers, and I think that only one of them was absolutely accurate in all of their answers. That subsystem of the language, which, at the very beginning, looked like a dynamic search for methods that could be influenced by help
.call()
, .bind()
or .apply()
began to look much more complicated after the appearance of arrow functions and classes. Apparently, it will be useful to note the main features of classes and arrow functions in terms of use
this
. Remember that arrow functions always use this
from their lexical scope, and the keyword this
in the classes is, in fact, tied to the constructor function of the class. And if you ever feel that you don’t know exactly whatthis
, use the debugger to check your assumptions on this subject. Also, keep in mind that you can do a lot in JavaScript without using it
this
in your code. Experience tells me that almost any JS code can be rewritten in the form of pure functions that take all the arguments that they work with, in the form of an explicitly specified list of parameters ( this
you can perceive an implicitly specified parameter with a mutable state). The logic contained in pure functions is deterministic, which improves their testability. Such functions do not have side effects, which means that when working with them, unlike manipulating with this
, you are unlikely to “break” anything outside of them. Always when you changethis
, you are faced with a potential problem, which is that something that depends on this
it may stop working correctly. Notwithstanding the foregoing, it should be noted that
this
this is a useful concept. For example, it can be used in order to organize the sharing of a certain method by a variety of objects. Even in functional programming, it this
can come in handy for calling other methods of an object from one method, which allows you to create something new based on existing structures.