15
Misconceptions of `this`
Hello friends,
let's start with what is not this
...
this
isn't bound to :
1- the object this
appears within.
2- the function this
appears within.
3- a new instance of the function this
appears within.
The keyword this
itself doesn't have a value. JS interpreter binds the value of this
when its parent function gets invoked. but would you always trust the JS interpreter to bind the value of this
to the right object
automatically? ... I wouldn't.
In other words, when someone shows you a code and asks you:
what is the value of
this
here ?
the right answer would be:
show me where the parent function is invoked.
I'll try to sum it up in 5 scenarios:
If the function is called with no context:
function displayName() {
console.log(this);
}
displayName(); // {}
In the code above, the value of this
inside displayName()
is either the global object
or, if in strict mode, it's undefined
.
If the function is a method of an object:
const player = {
name: "Mohamed",
displayName: function () {
console.log(this.name);
},
};
player.displayName(); // "Mohamed"
In the code above, the value of this
inside displayName()
will refer to player
which actually makes sense because you called the method displayName()
on the object player
. that invocation bound the object player
to this
inside of the method. good job JS interpreter.
function Square(color) {
this.color = color;
}
const redSquare = new Square("red");
let's see what the keyword new
does behind the scenes.
without using the keywords new
and this
, you will have to create and return the object manually
function Square(color){
let obj = {}
obj.color = color
return obj
}
const redSquare = Suare("red");
the keyword new
actually creates the object for you and binds that object to this
... then return it
function Square(color){
̶l̶e̶t̶ ̶t̶h̶i̶s̶ ̶=̶ ̶O̶b̶j̶e̶c̶t̶.̶c̶r̶e̶a̶t̶e̶(̶S̶q̶u̶a̶r̶e̶.̶p̶r̶o̶t̶o̶t̶y̶p̶e̶)̶; //{}
this.color = color;
̶r̶e̶t̶u̶r̶n̶ ̶t̶h̶i̶s̶;
}
const redSquare =new Square("red");
In the code above, the value of this
inside the function is a newly created empty object.
So far we have been saying that JS interpreter does all the work automatically for us... do we have control over the value of this ?
Actually, YES we do
we have two 3 methods to change the value of this
const player = {
name: "Mohamed",
displayName: function () {
console.log(this.name);
},
};
const anotherPlayer = { name: "ahmed" };
player.displayName.call(anotherPlayer); // "ahmed"
same as
player.displayName.apply(anotherPlayer)
In the code above, the value of this
inside displayName()
will refer to anotherPlayer
since the first parameter of call()
or "apply() is to explicitly set what this
refers to.
bind()
method is a little bit different because it returns the same function after it sets the value of this
to whatever you want
const player = {
name: "Mohamed",
displayName: function () {
console.log(this.name);
},
};
const anotherPlayer = { name: "ahmed" };
const displayName = player.displayName.bind(anotherPlayer);
displayName(); // "ahmed"
In the code above, bind()
set the value of this
inside player.display
to anotherPlayer
and returned a whole new function.
.... wait what ... why would I use bind()
...I'll stick to call()
and apply()
.
let's say you have this code, a simple function that takes a callback and call it twice.
const player = {
name: "Mohamed",
displayName: function () {
console.log(this.name);
},
};
function callTwice(cb) {
cb();
cb();
}
callTwice(player.displayName);
what do you expect ?? you passed the right function... but look where it's invoked !
the output would be according to rule number # 1
undefined
undefined
In the code above, the value of this
will be the global object because that's how its parent function got invoked.
Don't worry... bind()
to the rescue
const callback = player.displayName.bind(player);
callTwice(callback); // "Mohamed"
// "Mohamed"
With regular functions, the value of this
is set based on how the function is called. With arrow functions, the value of this
is based on the function's surrounding context. In other words, the value of this
inside an arrow function is the same as the value of this
outside the function then apply the rules we mentioned earlier.
1- Apply MDN
2- Call MDN
3- Bind MDN
15