DEV Community

Cover image for Understanding this in JavaScrip
Coding Jitsu
Coding Jitsu

Posted on

Understanding this in JavaScrip

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.
this // Window {0: Window, window: Window, self: Window,...
Enter fullscreen mode Exit fullscreen mode

We can also run console.log(this === window) // true

  1. 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.
function myFunc() {
    console.log(this);
}
myFunc(); // Window {0: Window, window: Window, self: Window,...,
Enter fullscreen mode Exit fullscreen mode

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

function myFunc() {
   'use strict';
   console.log(this);
}
myFunc(); // undefined
Enter fullscreen mode Exit fullscreen mode

Let's get another example:

function someFunc() {
   this.name = 'Rahim Shah';
}
someFunc();
window.name; // 'Rahim Shah'
Enter fullscreen mode Exit fullscreen mode

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

  1. As an object method When a function is called as a method of an object, it's thisis 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.
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'
Enter fullscreen mode Exit fullscreen mode

this binding is only affected by the most immediate member reference. In the following example, let's call a function in a nested object.

const customObj = {
   name: 'Rahim',
   occupation: 'Developer',
   nestedObj: {
       name: 'Karim',
       occupation: 'Engineer',
       message: function() {console.log('Hi, my name is ' + this.name);}
   }
}
Enter fullscreen mode Exit fullscreen mode

If we call customObj.nestedObj.message(); we will get 'Hi, my name is karim' back.

  1. 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:
class Example {
  constructor() {
     const proto = Object.getPrototypeof(this);
     console.log(Object.getOwnPropertyNames(proto));
  }
  first(){}
  second(){}
  static third(){}
}

new Example(); // ['constructor', 'first', 'second']
Enter fullscreen mode Exit fullscreen mode

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

  1. 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.
const customObj = {
   name: 'Rahim',
   occupation: 'Developer',
   nestedObj: {
       name: 'Karim',
       occupation: 'Engineer',
       message: function() {console.log('Hi, my name is ' + this.name);}
   }
}
Enter fullscreen mode Exit fullscreen mode

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.

customObj.nestedObj.message.call(customObj) // Hi, my name is Rahim
Enter fullscreen mode Exit fullscreen mode

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.

function someFunc() {
   return this.property;
}
const anotherObj = someFunc.bind({ property: 'some value'})
console.log(anotherObj()) // some value
Enter fullscreen mode Exit fullscreen mode
  1. 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:
const customObj = {
   name: 'Rahim',
   nestedObj = {
      name: 'Karim',
      msg: () => {console.log(this)}
   }
}
Enter fullscreen mode Exit fullscreen mode

If we runcustomObj.nestedObj.msg() will return window object in browsers.

Read about Closures in JavaScript.

Top comments (0)