Interview Question: Explain how `this` works in JavaScript [in 3 mins].
Tags: javascript, webdev, node, beginners
Published: 2022-07-20 09:50:56

In JavaScript, `this` is a property of the execution context in which a function is executed.

The explanation for how `this` gets evaluated is very elaborate, and it is covered case by case in [this MDN article](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) comprehensively.

The value of a function's `this` is determined mostly by how the function is being called in the **call site**, rather than how the function is **defined**: things like whether **strict mode** is enabled or not, whether the function is defined and called standalone or not, whether we are calling the function as a method of an object or if we are extracting a reference of an object method and then calling it somewhere else, etc.

### Execution Context
A function's execution context is the environment in which the function is executed at runtime. It includes, the variable scope, function arguments and the value of `this` object.

### `this`
If we need a function which acts on the properties of an object we want to use, its `this` ought to be that object. In other words, our function's target object has to be made available to the execution context at runtime, so that we are able to access it with `this`. 

In normal mode, `this` is always an object. `undefined` and `null` values are **autoboxed** to the global object (the `window` object in the browser). In strict mode, however, it can be `undefined` or `null`, as there is no autoboxing of `this` in strict mode.

```JavaScript
function testThis() {
  return this;
};
console.log(testThis()); // [object Window]

function testThisInStrictMode() {
  'use strict'
  return this;
};
console.log(testThis()); // undefined
```
### In Objects
If we have an object with a method that uses `this` and we call the method on the object, the object is automatically assigned to the method's `this`.

```JavaScript
const person = {
  name: 'Abd',
  age: 42,
  sayHi: function() {
    return `Hi, this is ${this.name}`;
  },
};

console.log(person.sayHi()); // "Hi, this is Abd"
```

The same applies to instances of custom objects created using constructor functions, as well as classes.

```JavaScript
// constructor function example
function Person() {
  this.name = 'Abd';
  this.age = 42;
  this.sayHi = function() {
    return `Hi, this is ${this.name}`;
  };
};
const person = new Person();
console.log(person.sayHi()); // "Hi, this is Abd"

// class example
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  };
  
  sayHi() {
    return `Hi, this is ${this.name}`;
  };
};

const person = new Person('Abd', 42);
console.log(person.sayHi()); // "Hi, this is Abd"

```
### Function References
Probably the most highlight-able case about `this` in JavaScript arises when we want to extract a reference of a method from an object and then call it from elsewhere.

For example, if we store the `sayHi()` method of the `person` object (from any of the examples above) in a variable and then invoke it later on, we will not have any object set for the method to act on. We are effectively detaching the object from the referenced function, so `this` for this function at runtime will be either the global object or `undefined` depending on whether in normal mode or strict mode.

```JavaScript
`use strict`
const sayHiAbd = person.sayHi; // Note that person.sayHi is NOT being invoked here
console.log(sayHiAbd()); // Error: Cannot read property 'name' of undefined

```
In this scenario, `sayHiAbd()` is like a standalone function defined as follows:

```JavaScript
function sayHiAbd() {
  return `Hi, this is ${this.name}`;
};
```

In such cases, we have to call the function using `.call()` or `.apply()` in order to set the `this` object explicitly at the call site.

```JavaScript
console.log(sayHiAbd.call({name: 'Abd', age: 42})); // "Hi, this is Abd"
```
### Binding Permanently
If we want to permanently bind an object to the function, we have to create a new function with `.bind()`, which attaches the object to the new function.

```JavaScript
const alwaysSayHiAbd = sayHiAbd.bind({name: 'Abd', age: 42});
console.log(alwaysSayHiAbd()); // "Hi, this is Abd"
```
### Arrow Syntax
The arrow syntax permanently binds the **enclosing lexical context** of the function definition to its execution context. So, the call site context never meddles with arrow functions.

In the object literal `person` example above, if we modify our `sayHi()` function to return an arrow function that returns the greeting string, the returned (arrow) function's `this` gets bound to its enclosing lexical context, which is the `person` object itself. Storing a reference to it and calling it always points its `this` to `person`.

```JavaScript
const person = {
  name: 'Abd',
  age: 42,
  sayHi: function() {
    return () => `Hi, this is ${this.name}`;
  },
};
const sayHiAbd = person.sayHi();
console.log(sayHiAbd()); // "Hi, this is Abd"

```

---
References
1. [this](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this)
2. [ECMAScript standard - ResolveThisBinding](https://tc39.es/ecma262/##sec-resolvethisbinding)