How to think about the JavaScript keyword 'this'
Tags: javascript, beginners
Published: 2020-06-28 14:10:46

The keyword *this* can be very useful, especially when creating classes or constructor functions, but it can be difficult to understand exactly what it's referring to sometimes because its meaning can change in different execution contexts within the program and with different patterns of invocation that may appear very similar when you're first exposed to them.


"Execution context" refers to the meaning and value of functions, objects, and variables, at a particular point in the program.  Because the Javascript compiler will read the code from top to bottom, the execution context, and therefore the value of these aspects, can change from one line to the next depending on how and when we invoke functions.  


There are four main patterns or styles of invoking functions in our programs.  Let's explore those and see how they can each change the meaning of *this* and what it will be bound to.


**Free Function/Global Invocation**

Unless we specify, the context of *this* is bound to the global object (which is the window object in the browser) by default.      


```javascript
function garfield () {
  console.log("mmm lasagna");
  console.log(this === window);
}
console.log(garfield()); //logs mmm lasagna true
```

Since we didn't specify what we referring to, this automatically was bound to the global window object.


**Method Invocation**


When we call on a function that is created inside of an object, we say we are invoking a method of that object.   


```javascript
const cat = {
  noise: 'meow',
  speak: function() {
    console.log(this.noise);
  }
}

console.log(cat.speak()); //logs meow
```

Above, we invoke speak, which is a method of our cat object.  Most of the time we can **look to the left of the dot at call time** of a function to see what *this* belongs to.  In our case, *cat* is to the left of the dot when we invoke the function speak, so we know that *this* is bound to it.


**Constructor Invocation**


Constructor functions allow us to create a sort of blueprint for making new objects that are related.  Instead of using camel case (camelCase) to declare a variable, we'll use an upper case letter to denote that this is a constructor function so other developers can tell right away that's its intended purpose.  Then we use the keyword *new* to create new instances of that object that will share the characteristics specified inside of the constructor.


```javascript
const Cat = function(breed, color) {
  this.breed = breed;
  this.color = color;
}

const myKitty = new Cat('Persian', 'white');
```

The *new* keyword lets us know that *this* will be bound to then newly-created object.

**.apply(), .call(), and .bind()**

Using *.apply()* or *.bind()* we can specify exactly what we want *this* to refer to, ensuring it will be what we intended and not a fun surprise.

*.apply()* takes two arguments- an object and an array of the arguments of the function we attach it to.  *.call()* works in the same way as *.apply*, except that the function arguments will be separated by commas and not inside of an array literal.  Both will invoke the function immediately.

```javascript
const person = {
    firstName: 'Jenny',
    lastName: 'Smith'
}

function feed(greeting, foods) {
    return `${greeting}, human called ${this.firstName}.
            Feed me ${foods} now, or else.`;
}

console.log(feed.apply(person, ['Good morning', 'wet food and treats']));
//Good morning, human they call Jenny. Feed me wet food and treats now, or else.
```

Using *.apply()*, we specified that *this* would refer to our person object and we gave our feed function the arguments in the array. 


What if you want to hang on to that context and re-use it? Instead of having to use *.apply()* or *.call()* over and over again, we can just use *.bind()* to return a function that will always have our specified context of *this* and save it with a variable.

```javascript
const demands = feed.bind(person, ['Good morning', 'wet food and treats'])

console.log(demands());
```

This will give us the same output as the *.apply()* approach we used above, but with a lot less code to write.  Each time we want to use it, we can simply invoke *demands()* and get the desired output for less work.


*this* can be a powerful tool for creating, using, and manipulating objects in JavaScript, but it takes some time and experimentation to learn how to use it correctly. Once we do, it can be a powerful tool in our developer toolbelts.