JavaScript: Simplifying 'this'
Tags: javascript, webdev, beginners
Published: 2021-07-26 21:07:46

## The Basics

`this` in any scope is equivalent to the object, implicitly it's the object from it is being call called as you must have read `this` depends on the call site, how and where the function is being called. Explicitly you can set `this` too, using `bind`, `call` or `apply` we will cover these later.

A simple example

```js
var obj = {
  age: 2,
  printAge: function () {
    console.log(this.age);
  },
};

obj.printAge(); // 2
```

### Arrow functions

Arrow functions are not just syntactical sugar over the normal function apart from other differences, one major difference is value of `this` it follows the lexical static binding i.e. `this` is not dynamic anymore. `this` is same as `this` of outer lexical scope. What does outer lexical scope mean?

Scope of the the parent function!

```js
const x = {
  y: 2,
  x1: {
    m1: () => console.log(1, this),
  },
  x2: function () {
    const y2 = {
      m1: () => console.log(2, this),
      m2: function () {
        const y3 = {
          m3: () => console.log(3, this),
        };
        return y3;
      },
    };
    return y2;
  },
};

x.x2().m1(); // 2, {y: 2, x1: Object, x2: ƒ x2()}
x.x2().m2().m3(); // 3, {m1: ƒ m1(), m2: ƒ m2()}
```

---

All function which are defined on top level are defined on `window` object hence `this === windows` for top level functions. `this` is `undefined` with **strict mode** enabled or with modules.

Let's take an example

```js
var a = 1;

function incA() {
  this.a = this.a + 1;
}

incA();

console.log(a); // 2
```

> Note: The above example holds only for "script" not "module", it will work in browser console's but not in CodeSandBox for the same reason.

## Class and "this"

There are some rules, relevant one for our discussion are

1. Arrow function can't be used as constructor.
2. `this` in arrow will be equal to the instance of this class. How? Checkout: [Transpiled code sample for Class](https://babeljs.io/repl/#?browsers=ie%2011&build=&builtIns=false&corejs=3.6&spec=false&loose=false&code_lz=MYGwhgzhAEAa0G8BQ1oEgB2YC2BTaAvNAEwDcSaeALgBYD2AJgIwAUAlMqqmsHRhHRC4AdCDoBzFrQCWEYVjxtyXaAF8U6avQbFC0doQB8iDd179BIsZJlyFuJabVJ1QA&debug=false&forceAllTransforms=false&shippedProposals=false&circleciRepo=&evaluate=false&fileSize=false&timeTravel=false&sourceType=module&lineWrap=true&presets=env%2Creact&prettier=false&targets=&version=7.14.8&externalPlugins=%40babel%2Fplugin-proposal-class-properties%407.13.0%2C%40babel%2Fplugin-proposal-object-rest-spread%407.13.8)

Let's take an example

```js
class X {
  name = 2;
  method1() {
    console.log(this.name);
  }
  method2 = () => {
    console.log(this.name);
  };
}

const z = new X();
z.method1(); // 2
z.method2(); // 2
```

let's add two more method

```js
class X {
  name = 2;
  method1() {
    console.log(this.name);
  }
  method2 = () => {
    console.log(this.name);
  };
  method3() {
    this.method1();
  }
  method4 = () => {
    this.method2();
  };
}

const z = new X();
z.method3(); // 2
z.method4(); // 2
```

Still nothing changes as `method3` is being called for the the object (`z`) itself so it got the context and `method4` has static binding.

Add the following code in the end:

```js
const method5 = z.method3;
const method6 = z.method4;

method6(); // 2
method5(); // TypeError: Cannot read property 'method1' of undefined
```

As `method5` has now lost the context it can't point to `this`, you must be wondering why it throws error instead of `undefined` as we discussed initially!

Module ? Nope, not this time!

It's due to implementation of class. Class are defined as function inside immediately invoked function expression.

That's why it's important to bind function in React. Not all but only those which will be passed to event handler or similar pattern as they are gonna loose the context of the component instance or use **arrow** functions.

## Overriding "this"

There might be a case where you would like to call a method from one object with another object for example

> This example will be used throughout the section

```js
const square1 = {
  side: 5,
  getArea: function () {
    return this.side * this.side;
  },
};

const square2 = {
  side: 10,
};

console.log(square1.getArea()); // 25
console.log(square1.getArea.call(square2)); //100

// This will work as well
const getArea = square1.getArea;
console.log(getArea.call(square2)); //100

// This too
const getArea2 = square1.getArea.bind(square2);
console.log(getArea2()); //100
```

### bind vs call

With `call` you can specify the object while calling a method and with each call you can pass another object.

```js
const square3 = {
  side: 20,
};
console.log(getArea.call(square3)); //400
```

`bind` is one time contract, once a method have formed bond with an object, it can't be broken, you cannot `bind` that again or use `call` on it.

```js
// const getArea2 = square1.getArea.bind(square2);
console.log(getArea2()); //100
console.log(getArea2.call(square3));

const getArea3 = getArea2.bind(square3); // 100
console.log(getArea3()); // 100
```

`apply` is same as `call`, it just expects array of parameters instead of individual parameters.

--EOF--