# Simplifying "this" in JavaScript

## Overview

The `this` keyword can be one of the most confusing concepts in JavaScript. We will explain this `this` in layman's terms with enough examples.

> `this` is the object the function is a property of

One liner,

```js
obj.someFunc(this);
```

Here, `this` is in the function `someFunc` and the `someFunc` is a property of `obj`. So `this` represents the `obj`.

# Examples

## **Local Object**

```js
const myObject = {
  name: 'foo',
  task: function () {
    return `This is ${this.name} task.`;
  }
};

myObject.task();
```

This will return the text `This is foo task.`.

By definition, here `this` refers to the object `myObject`. The function of `task` is the property of `myObject`.

---

## **Global Object**

In the global scope, `this` is the `window` object.

In the global scope, if we define a function

```js
function a() {
  console.log(this);
}
```

It will print the `window` object.

Since the `a()` method is `window.a()`, so according to our first definition, for `a()`, `this` is the `window` object.

---

## **"this" is determined by Who Called the method?**

`this` is defined by the object called the method.

```js
const a = function () {
  console.log('For a, this is ', this);
  const b = function () {
    console.log('For b, this is ', this);
    const c = {
      hi: function () {
        console.log('For c, this is ', this);
      }
    };
    c.hi();
  };
  b();
};

a();
```

In this case, both `a` and `b` has the `window` object as `this`.

And for `c`, since it is invoked by `c`, then, the `this` is the `c` object.

Now, query might be, how `b()` has the `this` object `window`, not the `a`. Because `b()` is not invoked by in similar way `a.b()`. Instead, it is invoked like `window.a(b())`

---

## **"this" is not lexically scoped, it is dynamically scoped**

```js
const obj = {
  name: 'Billy',
  sing() {
    console.log('a', this);
    var anotherMethod = function () {
      console.log('b', this);
    };
    anotherMethod();
  }
};

obj.sing();
```

Here for `a`, the `this` context is `obj`.

For `b`, the `this` context should be `obj`. But since `this` is not lexically scoped and follows method calls, `b` has the `this` context of `window`.

This is why `this` follows the `dynamic scoped` instead of `lexical scoped`.

---

# Preserve this context

We can preserve `this` context,

* By preserving it in a variable
    
* Using the arrow method
    
* Using bind method (Ex. first bind and then obj.prop()())
    

To solve this `dynamic scope` issue, we can use the `arrow method`. `Arrow method` is bound to the `lexical scoped`.

**Using the Arrow method:**

```js
const obj = {
  name: 'Billy',
  sing() {
    console.log('a', this);
    var anotherMethod = () => {
      console.log('b', this);
    };
    anotherMethod();
  }
};

obj.sing();
```

Here both `a` and `b` have the `this` context of `obj`.

**Using bind:**

Another was to make the `this` to `lexical scoped` using `bind()` method.

```js
const obj = {
  name: 'Billy',
  sing() {
    console.log('a', this);
    var anotherMethod = function () {
      console.log('b', this);
    };
    return anotherMethod.bind(this);
  }
};

obj.sing()();
```

Here `a` and `b` has the `this` context of `obj`.

**Preserving in lexical scope:**

Holding the `this` in another object can be used to preserve the `this` context.

```js
const obj = {
  name: 'Billy',
  sing() {
    console.log('a', this);
    var self = this;
    var anotherMethod = function () {
      console.log('b', self);
    };
    anotherMethod();
  }
};

obj.sing();
```

Here both `a` and `b` have the `this` context of `obj`.

## Manipulating "this"

We can manipulate/change the `this` keyword using the following methods,

* call
    
* apply
    
* bind
    

**Using call method:**

We can use use the `call` method to invoke a method, like the following,

```js
var myMethod = function () {};
// following both statements are similar
myMethod();
myMethod.call();
```

We will use the same mechanism to inject the `this`,

```js
const wizard = {
	name: 'Wizard',
	health: 50,
	heal() {
	  this.health = 100;
	}
};

const archer = {
	name: 'Archer',
	health: 30
};

wizard.heal.call(archer);
console.log(archer);
```

This will print,

```bash
{
	name: 'Archer',
	health: 100
}
```

Here the health property is the same as the `wizard` object.

Now, let's see another example of passing parameters using the `call` method.

```js
const wizard = {
  name: 'Wizard',
  health: 50,
  heal(param1, param2) {
    this.health = this.health + param1 + param2;
  }
};

const archer = {
  name: 'Archer',
  health: 30
};

wizard.heal.call(archer, 10, 20);
console.log(archer);
```

This will add the params `10` and `20` with it existing value `30`.

So the printed value is,

```bash
{
  name: 'Archer',
  health: 60
}
```

**Using apply**

`apply()` is similar to `call()`, it uses `call()` underlying. The only difference between `call()` and `apply()` is, in `apply()`, the parameter is passed through the parenthesis.

```js
var myMethod = function () {};
// following both statements are similar
myMethod();
myMethod.apply();
```

We can update/change the `this` using the `apply`, as follows,

```js
const wizard = {
  name: 'Wizard',
  health: 50,
  heal(param1, param2) {
    this.health = this.health + param1 + param2;
  }
};

const archer = {
  name: 'Archer',
  health: 30
};

wizard.heal.apply(archer, [10, 20]);

console.log(archer);
```

This will print the same value as the previous `call()` method.

```bash
{
  name: 'Archer',
  health: 60
}
```

**Using bind**

Except for the `call()` and `bind()`, the `bind()` does not invoke the method instantly. Instead, it returns a method that can be invoked later.

```js
const wizard = {
  name: 'Wizard',
  health: 50,
  heal(param1, param2) {
    this.health = this.health + param1 + param2;
  }
};

const archer = {
  name: 'Archer',
  health: 30
};

const archerHeal = wizard.heal.bind(archer, 10, 20);
archerHeal();

console.log(archer);
```

This will print the same value as the previous `call()` or `apply()` method.

```bash
{
  name: 'Archer',
  health: 60
}
```

We can make use of `bind` and reach an interesting pattern. Let's we have a method that takes two numbers and returns the multiplied result.

```js
const multiplyMethod = (num1, num2) => {
  return num1 * num2;
};
```

Now using the function bind, we will create two methods from the previous method. Both methods will provide only one parameter.

* One will return multiply with 4
    
* Another will return multiplied with 10
    

```js
let multiplyByTwo = multiplyMethod.bind(this, 4);
let multiplyByTen = multiplyMethod.bind(this, 10);

console.log(multiplyByTwo(2));
console.log(multiplyByTen(2));
```

This will return,

```bash
8
20
```

## Benefits

**Allow methods to use the properties of the object itself**

```js
const myObject = {
  name: 'foo',
  task: function () {
    return `${this.name} task.`;
  },
  doTask: function () {
    return `Do ${this.task()}`;
  }
};

myObject.doTask();
```

This will return `Do foo task.`

**Execute the same code for multiple objects**

```js
function showMyName() {
  console.log(this.name);
}

const foo = {
  name: 'foo',
  showMyName
};

const bar = {
  name: 'bar',
  showMyName
};

foo.showMyName();
bar.showMyName();
```

This will return

```bash
foo
bar
```

## Brain Teaser

Let's observe, a couple of examples

**Example 01**:

```js
const myObj = {
  name: 'myName',
  myMethod() {
    console.log(this);
  }
};

myObj.myMethod();
```

Here the `this` is the `myObj` itself.

**Example 02**:

```js
const myObj = {
  name: 'myName',
  myMethod() {
    return function () {
      return console.log(this);
    };
  }
};

myObj.myMethod()();
```

Since the return function is not called by the `myObj`, here the `this` object is the `window`. It is using `dynamic scope` instead of `lexical scope`.

**Example 03**:

```js
const myObj = {
  name: 'myName',
  myMethod() {
    return () => {
      return console.log(this);
    };
  }
};

myObj.myMethod()();
```

Since, the `arrow method` strictly maintains the `lexical scope`, here the `this` represents the `myObj`.

**Example 04: Classes are by default \`use strict;\`**

In ES2015 classes, `this` behaves as it does in object methods. It refers to the instance of the class.

```typescript
class Person {  
    constructor(name) {    
        this.name = name;  
    }
    showThis() {    
        console.log(this);  
    }
}
const person = new Person('John');
person.showThis(); // Person {name: 'John'}
const showThisStandalone = person.showThis;
showThisStandalone(); // `undefined` because all parts of a class' body are strict mode.
```

Example 05: **When Multiple Rules Apply \[Rules from summary\]**

When multiple rules apply, the rule higher on the list wins.

```typescript
var obj1 = {
    value: 'hi',
    print: function() {
        console.log(this);
    },
};
var obj2 = { value: 17 };
```

If rules 2 and 3 both apply, rule 2 takes precedence.

```typescript
obj1.print.call(obj2); // -> { value: 17 }
```

If rules 1 and 3 both apply, rule 1 takes precedence.

```typescript
new obj1.print(); // -> {}
```

# Summary

1. If the `new` keyword is used when calling the function, meaning the function was used as a function constructor, the `this` inside the function is the newly-created object instance.
    
2. If `this` is used in a `class` `constructor`, the `this` inside the `constructor` is the newly-created object instance.
    
3. If `apply()`, `call()`, or `bind()` is used to call/create a function, `this` inside the function is the object that is passed in as the argument.
    
4. If a function is called as a method (e.g. `obj.method()`) — `this` is the object that the function is a property of.
    
5. If a function is invoked as a free function invocation, meaning it was invoked without any of the conditions present above, `this` is the global object. In the browser, the global object is the `window` object. If in strict mode (`'use strict';`), `this` will be `undefined` instead of the global object.
    
6. If multiple of the above rules apply, the rule that is higher wins and will set the `this` value.
    
7. If the function is an ES2015 arrow function, it ignores all the rules above and receives the `this` value of its surrounding scope at the time it is created.
    

References

1. [GreatFrontend](https://www.greatfrontend.com/questions/quiz/explain-how-this-works-in-javascript)
    
2. [**Arnav Aggrawal's article on Medium**](https://codeburst.io/the-simple-rules-to-this-in-javascript-35d97f31bde3)
