Understanding this in JavaScrip
Tags: javascript, webdev, beginners, programming
Published: 2022-11-25 17:41:01

One of the confusing topics in JavaScript is the 'this' keyword. A function's 'this' keyword behaves a little differently in JS compared to other languages. It also has some differences between strict mode and non-strict mode. Let's learn all about them in this article.
`this` in JavaScript is a reserved keyword. In most cases, the value of `this` is determined by how a function is called(runtime binding). It can't be set by assignment during execution, and it may be different each time the function is called. The `bind()` method can set the value of a function's `this` regardless of how it's called, and arrow functions don't provide their own `this` binding. Let's see how `this` behaves in different contexts.

1. **Global context** In the global execution context (outside of any function), `this` refers to the global object whether in `strict mode` or not. We can see this by simply typing `this` in the devtools of the browser.
```js
this // Window {0: Window, window: Window, self: Window,...
```
We can also run `console.log(this === window) // true`

2. **Function context** Now, if we log `this` inside a function, we are going to get two different outputs based on if we are in `strict mode` or not.

```js
function myFunc() {
    console.log(this);
}
myFunc(); // Window {0: Window, window: Window, self: Window,...,
```
So in a non-strict mode, we are getting the same global object in the case of browsers - it is window object like before. In JavaScript `this` first looks for the `value` in the function curly braces, when it does not find any `value` there, then it goes outside of the function scope and looks for the `value` which is in the global context of the global object. This behavior of `this` could be a source of a bug. So, in order to solve the issue, we can use `use strict`

```js
function myFunc() {
   'use strict';
   console.log(this);
}
myFunc(); // undefined
```
Let's get another example:

```js
function someFunc() {
   this.name = 'Rahim Shah';
}
someFunc();
window.name; // 'Rahim Shah'
```
As you can see from the above example `this.name` attached the `name` with the global object which is the `window` object in the browser. In case of strict mode it will throw a `TypeError: Cannot set properties of undefined`

3. As an object method When a function is called as a method of an object, it's `this`is set to the object the method is called on. In the following example, when `customObj.message()` is invoked, inside the function `this` is bound to the `customObj` object.

```js
const customObj = {
    name: 'Rahim',
    occupation: 'Developer',
    message: function() {
       console.log('Hey! my name is', this.name + ' and I am a ' + this.occupation);
  }
}
customObj.message(); // 'Hey! my name is', Rahim and I am a Developer'
```
`this` binding is only affected by the most immediate member reference. In the following example, let's call a function in a nested object.

```js
const customObj = {
   name: 'Rahim',
   occupation: 'Developer',
   nestedObj: {
       name: 'Karim',
       occupation: 'Engineer',
       message: function() {console.log('Hi, my name is ' + this.name);}
   }
}
```
If we call `customObj.nestedObj.message();` we will get `'Hi, my name is karim'` back.

4. **Class context** The behavior of `this` in classes and functions is similar since classes are functions under the hood. Within a class constructor, `this` is a regular object. All non-static methods within the class are added to the prototype of `this`:

```js
class Example {
  constructor() {
     const proto = Object.getPrototypeof(this);
     console.log(Object.getOwnPropertyNames(proto));
  }
  first(){}
  second(){}
  static third(){}
}

new Example(); // ['constructor', 'first', 'second']
```

> **Note**: Static methods are not properties of this. They are properties of the class itself.

5. The `bind()`, `call()`, `apply()` method We can specifically bind `this` to an object with the `call()`, or `apply()`method. For an example let's take our previous example of nested object.

```js
const customObj = {
   name: 'Rahim',
   occupation: 'Developer',
   nestedObj: {
       name: 'Karim',
       occupation: 'Engineer',
       message: function() {console.log('Hi, my name is ' + this.name);}
   }
}
```
If we run `customObj.nestedObj.message()` we are going to get the name printed as 'karim' but what if we want the 'Rahim' name instead? We can use the `call()` method to achieve the desired result.

```js
customObj.nestedObj.message.call(customObj) // Hi, my name is Rahim
```
`apply()` method will get the same result as above. Let's look at the `bind()` method. Calling `someFunc.bind(someObj)` creates a new function with the same body and scope as `someFunc`, but where `this` occurs in the original function, in the new function it is permanently bound to the first argument of `bind`, regardless of how the function is being used.

```js
function someFunc() {
   return this.property;
}
const anotherObj = someFunc.bind({ property: 'some value'})
console.log(anotherObj()) // some value
```
6. **Arrow functions** In arrow functions, `this` will be set to the global object in the global code. In the following code, `this` will return undefined:

```js
const customObj = {
   name: 'Rahim',
   nestedObj = {
      name: 'Karim',
      msg: () => {console.log(this)}
   }
}
```
If we `runcustomObj.nestedObj.msg()` will return `window` object in browsers.

Read about [Closures in JavaScript](https://www.tanveersayem.io/blogs/what-is-closures-in-javascript).