Understanding 'this'
Tags: javascript, webdev, this, beginners
Published: 2020-11-30 05:28:06

One of the most confusing mechanisms in JavaScript is `this` keyword. Even a seasoned developer can get bewildered sometimes. So, let’s see if it's really that complicated!

**`this` is a special keyword that’s automatically defined in the scope of every function**. But how JavaScript engines decide what value should it assign to `this`.

##Default Binding
In default binding, `this` refers to the global object. Any plain undecorated function call will invoke default binding if the scope in which `this` is used is not using `strict mode`. Consider:

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

var a = 2;

foo(); // 2
```
Variables declared in global scope as `var a = 2`, `function foo() {…}` are synonymous with global-object properties of the same name. **They are not copies of each other, they are each other**. In this snippet `foo()` is called with a plain, undecorated function reference. Hence, the default binding applies here i.e., global object.

If `strict mode` is in effect, the global object is not eligible for the default binding, so the `this` is instead set to `undefined`.

```js
function foo() {
  "use strict";
  console.log(this.a);
}

var a = 2;

foo(); // TypeError: 'this' is 'undefined'
```
Although overall `this` binding rules are entirely based on the call-site, the global object is only eligible for the default binding if the contents of `foo()` are not running in `strict mode`. The `strict mode` state of the call-site of `foo()` is irrelevant.

##Implicit Binding
Implicit binding is invoked if the call-site has a context object. Now, what’s a context object! 
Consider:

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

var obj = {
  a: 2,
  foo: foo
};

obj.foo(); // 2
```
Here the call-site uses the `obj` context to reference the function, so we can say `obj` 'owns' or 'contains' the function reference at the time function is called. Now consider this:

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

var obj = {
  a: 12,
  foo: foo
};

var obj1 = {
  a: 2,
  obj: obj
};

obj1.obj.foo(); // 12
```
This may look confusing but only the last level of an object property reference chain matters to the call-site. So `this` in `foo()` refers to obj for the above function call.

###Gotchas
Consider the following code:
```js
function foo() {
  console.log(this.a);
}

var obj = {
  a: 2,
  foo: foo
}

var bar = obj.foo;

var a = 'Oops, global';

bar(); // 'Oops, global'
```

Even though `bar` appears to be a reference to `obj.foo`, in fact, it’s really just another reference to `foo` itself. Moreover, the call-site is what matters, and the call-site is `bar()`, which is a plain, undecorated call, and thus the default binding applies.

There is one more way to lose implicit binding i.e. when we are using callbacks. You don’t know how your passed function is being called in the callback. *Trust issues* 😐️

###Are default and implicit binding the same?
Consider the following code:

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

var a = 2;

window.foo(); // 2
```
As discussed earlier variables declared in the global scope are synonymous with global-object properties of the same name. We can refer to these variables as `window.a`, `window.foo` respectively.

So whenever we are using plain, undecorated functions calls that means its context object is window and hence we get `window` as `this` in those cases.

##Explicit Binding
Now let’s take the controls into our hands 😎️.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/40jcm4g487maqz8uimji.gif)

Functions have some utilities available to them (via their `[[Prototype]]`), which can be useful for this task. Specifically `bind(…)`, `call(…)`, and `apply(…)` methods.

###call(), apply() & bind()
* We can specify what we want our `this` to be, using these functions.
* One common thing about these functions is, it takes the first parameter - an object which is assigned as `this` on function invocation.
* `call()` & `apply()` invokes the function immediately while `bind()` just returns a new function.

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

var obj = {
  a: 2
};

foo.call(obj); // 2
foo.apply(obj); // 2

var bar = foo.bind(obj);

bar(); // 2
```
These are very useful functions in JavaScript and can’t be covered in this post so we’ll talk about these functions in-depth in another article.

##new Binding
When a function is invoked with `new` in front of it, the following things happen:
* A brand new object is created out of thin air.
* The newly constructed object is set as the `this` binding for that function call.

```js
function foo(a) {
  this.a = a;
}

var bar = new foo(2);

console.log(bar.a); // 2 
```
The `new foo(2)` will return `{a:2}` in the above snippet.

There are few other things that happen too, but that is out of scope for this topic.

##Conclusion
Once you know the call-site of a function, 4 rules can be applied to the call-site, in this order of precedence to determine `this` binding:
* Called with `new`? Use the newly constructed object.
* Called with `call()`, `apply()`, `bind()` ? Use the specified object.
* Called with context object owning the call? Use that context object.
* Default: `undefined` in `strict mode`, global object otherwise.

For a more in-depth understanding of `this` I highly recommend reading **this & OBJECT PROTOTYPES** of **YOU DON’T KNOW JS** series by **Kyle Simpson**.