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:

1. The global object or undefined

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.

2. A context object

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.

3. A new object

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.

4. A specified 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

.call() and .apply() methods

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()

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"

5. this inside arrow function

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.

for more readings

14