DEV Community

Cover image for My Widow's mite: The "this" keyword in Javascript
Qliqsee
Qliqsee

Posted on

My Widow's mite: The "this" keyword in Javascript

“Truly I tell you, this poor widow has put more into the treasury than all the others.
They all gave out of their wealth; but she, out of her poverty, put in everything— all she had to live on.”

Mark 12: 43-44

Warning, this is the most naïve approach but in the end, I hope to better help you understand the this keyword even in cases where it proves most elusive to understand.

I'm writing this passionately because I've witnessed firsthand, the muddling that comes with the this keyword in context and reference.

The word This by itself is a demonstrative pronoun which is used for indicating (point to) something. To understand you need to first grasp the concept of pronouns and how it saves you from looking like a complete fool on a daily basis 😁.

Consider this example: Richard scored highest in the test because Richard read all through the night.

Implementing the concept of pronouns as a sane person would, we write: Richard scored highest in the test because he read all through the night.

Notice how we didn't reuse Richard, we do this because we don't want people to run away from us. Trust me, any guy that does otherwise should bid farewell to his chances of landing a pretty model-like girlfriend 🤦‍♂️.

So it is in JavaScript and programming in general, hence the need for a referent. The this basically refers to an object (an antecedent) which is the subject in the context of an executing code.

Here is an example to help you further understand:

let person = {
    name: 'Richard Doe',
    job: 'Farming',
    jobFunction: function () {
      console.log(`${this.name}'s occupation is ${this.job}`);
    },
  };
  person.jobFunction(); //Richard Doe's occupation is Farming

  // But of course this would also work
  let person = {
    name: 'Richard Doe',
    job: 'Farming',
    jobFunction: function () {
      console.log(`${person.name}'s occupation is ${person.job}`);
    },
  };
  person.jobFunction(); //Richard Doe's occupation is Farming
Enter fullscreen mode Exit fullscreen mode

Our code becomes superfluous writing it the second way as person.name and person.job, definitely a turnoff 🤮. Especially since there could be another global variable person that we might not be aware of and this could lead to difficult-to-debug errors in our code. So we use the this keyword to avoid ambiguity and emphasize precision, yeah and also for aesthetics (at least in my own case).

Like objects all JavaScript functions have properties. And when executing, they get the this property __ a variable with the value of the object that invokes the function where this is used.

When in strict mode, "this" holds the value of undefined in the global scope and anonymous in functions that aren't bound to any object.

GOTCHA

To expunge every confusion it is important that you understand this one principle; this is not assigned a value until an object invokes the function where this is defined.
In most cases this assumes the value of the object that invokes it. There are only few instances or scenarios when this does not have the value of the invoking object and I'll touch on some of them here and drop a link to an article for a more in-depth and probably more comprehensive article.

this in global scope

This is getting too lengthy yeah? Just one more section with few points and we are done, Arigato 🙏.

In the global scope all global variables and functions are defined in the window object. Hence, in the global scope this will have the value of the global window object (except in strict mode).

  // in the global scope
function print() {
    this.color = 'purple';
    console.log(this.color);
  }
  print(); //purple
Enter fullscreen mode Exit fullscreen mode

in strict mode:

 function print() {
    'use strict';
    this.color = 'purple';
    console.log(this.color);
  }
  print();//Cannot set property 'color' of undefined
Enter fullscreen mode Exit fullscreen mode

Here comes the tricky part, now I'll be touching on some scenarios where the this keyword becomes confusing.

  • When "this" is used in a method passed as a callback.

Things get touch hairy when we pass a method (that uses this) as a parameter to be used as a call back function.

Here is an example:

 // here is an object with a clickhandler method that is called when a button is clicked
  var person = {
    farmers: [{ name: 'Richard Doe', job: 'Farmer' }],
    clickHandler: function () {
      console.log(`${this.farmers[0].name} is a ${this.farmers[0].job}`);
    },
  };
  let button = document.getElementById('button'); //button here is an object
  button.addEventListener('click', person.clickHandler); //the click() method here is a method on the button object and
  // Cannot read property '0' of undefined because there is no farmers property on the button object
Enter fullscreen mode Exit fullscreen mode

this here is undefined because button is an object all by itself and person.clickHandler() is a method we are passing to button's click method as a callback. This implies that the person.clickHandler() will no longer refer to the person object. this here will now refer to the object where the person.clickHandler() method is executed which is the button object.

Hence it is lucid that when the context changes the this keyword will no longer refer to the object where this was originally defined but to the object that invokes the method where this was defined.

An approach to resolving this problem is to use the bind method. We will bind the clickhandler() method to the person object.

Here is an example:

 // An alternative approach
  var person = {
    farmers: [{ name: 'Richard Doe', job: 'Farmer' }],
    clickHandler: function () {
      console.log(`${this.farmers[0].name} is a ${this.farmers[0].job}`);
    },
  };
  let button = document.getElementById('button'); //button here is an object
  button.addEventListener('click', person.clickHandler.bind(person)); //the click() method here is a method on the button object and
  //Richard Doe is a Farmer
Enter fullscreen mode Exit fullscreen mode
  • When this is used inside a closure

Closures are inner functions basically and it is expedient you grasp that closures can't access the this variable of outer functions by using the this keyword because the this varaible can be accessed only by the function itself.

See this:

  var person = {
    farmersMotto: 'Farming is our pride',
    farmers: [
      { name: 'Richard Doe', job: 'Farmer' },
      { name: 'Rachael Doe', job: 'Farmer' },
    ],
    clickHandler: function () {
      this.farmers.forEach(function () {
        console.log(`Our motto as farmers is ${this.farmersMotto}`); //Our motto as farmers is undefined
        //why?
        console.log('' + this); // [object window]
      });
    },
  };
  person.clickHandler();
Enter fullscreen mode Exit fullscreen mode

this inside an anonymous function is bound to the global window object because it cannot access the outer function's this(when strict mode is not in use)

Resolving this on the other hand is quite easy, just set the this value to a variable before entering the anonymous function. This is a fairly popular approach amongst developers.

See this:

 var person = {
    farmersMotto: 'Farming is our pride',
    farmers: [
      { name: 'Richard Doe', job: 'Farmer' },
      { name: 'Rachael Doe', job: 'Farmer' },
    ],
    clickHandler: function () {
      var thisPerson = this;
      this.farmers.forEach(function () {
        console.log(`Our motto as farmers is: ${thisPerson.farmersMotto}`); //Our motto as farmers is: Farming is our pride
      });
    },
  };
  person.clickHandler();
Enter fullscreen mode Exit fullscreen mode
  • this when a method is assigned to a variable

Here is an example:

  // This data variable is a global variable
  var farmers = [{ name: 'Rachael Doe', job: 'Farming' }];

  var person = {
    // this data variable is a property on the Person object
    farmers: [{ name: 'Richard Doe', job: 'Farming' }],
    showData: function (event) {
      console.log(`${this.farmers[0].name}'s job is ${this.farmers[0].job}`);
    },
  };

  // Assign the person.showData to a variable
  var showPersonsData = person.showData;

  //
  showPersonsData(); // Rachael Doe's job is Farming (from the global data array)
  //The output we desire is: Richard Doe's job is Farming. 
  //so how do we fix this?
Enter fullscreen mode Exit fullscreen mode

A quick fix to this will be to use the bind method.

Like this:

  // This data variable is a global variable
  var farmers = [{ name: 'Rachael Doe', job: 'Farming' }];

  var person = {
    // this data variable is a property on the Person object
    farmers: [{ name: 'Richard Doe', job: 'Farming' }],
    showData: function (event) {
      console.log(`${this.farmers[0].name}'s job is ${this.farmers[0].job}`);
    },
  };

  // Assign the person.showData to a variable
  var showPersonsData = person.showData.bind(person);

  //
  showPersonsData(); // Richard Doe's job is Farming (from the global data array)
Enter fullscreen mode Exit fullscreen mode

Of course, there are other cases of the Javascript this keyword errors and fixes. I recommend you read this article for an in-depth understanding of the this keyword.

Final Note

Alt Text

I'm inexperienced myself but I hope I have been able to help you out with the little I know. Lemme know what you think 👋.

In everything I did, I showed you that by this kind of hard work we must help the weak, remembering the words the Lord Jesus himself said: ‘It is more blessed to give than to receive.

Act 20:35

Discussion (4)

Collapse
gauravshekhawat profile image
Gaurav-Shekhawat

Ahh, the title magic

Collapse
agboola_iyanu profile image
Qliqsee Author

Does the work well

Collapse
otinomz profile image
Exhale Words

beautiful

Collapse
agboola_iyanu profile image
Qliqsee Author

thanks man.