DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 963,274 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Naim Latifi
Naim Latifi

Posted on • Updated on

Understanding "this" in JavaScript

Many times this keyword in JavaScript can be confused if it is not understood correctly. In this article, I will show you how this works with some code examples and how its value is assigned in a different context in JavaScript. There are different scenarios where this can change its value:

      - `this` in a global context, function invocation

      - `this` in an object constructor

      - `this` in an object method.

      - `this` with arrow function (=>) 
Enter fullscreen mode Exit fullscreen mode

But wait before jumping to the examples we just mentioned context so what is it in JavaScript? The context in JavaScript is always the value of this that is determined during the execution code. To clearly understand let's go now with code examples and see how it works on each scenario.

console.log("What is 'this' value?", this) // Window
function simpleFunction () {
   console.log("What is the value of this inside function?", this) //  Window
  }
simpleFunction()
Enter fullscreen mode Exit fullscreen mode

From the code example 1 this refers to the global object which is determined from the execution context and wherein the browser is the global object (window). Similarly, when invoking the function this inside that function refers to the global object. But what this refers inside constructor function? We see this in the code example 2 as below.

function Person(name, lastName) {
    this.name = name;
    this.lastName = lastName;
    this.displayName = function() {
       console.log(`Your name ${this.name} and lastName 
     ${this.lastName}`)
  }
}
  let person = new Person('George', 'Superman')
      person.displayName() // George Superman
Enter fullscreen mode Exit fullscreen mode

As we see from the code above we create a construction function Person and then we invoke a new instance object george. this value, in this case, refers to the newly created object.

let greetings = {
     word: 'Hello',
     printGreeting: function(){
       console.log("What 'this' refers to inside object method? ", 
   this.word) // "this" in object refers to the object itself- greetings
     }
  }

  greetings.printGreeting()
Enter fullscreen mode Exit fullscreen mode

From code example 3 above we created an object which has a property and method printGreeting. We are calling the property name inside the method with this which its value refers to the object itself.

We saw from the code examples above that this value inside a function refers to the global object and inside of an object method refers to the object itself but what about if we want to invoke an object method inside another function and reference this. What will be the value of this in this context? Let's see with the code example 4 and where we will run it with strict mode as below

"use strict"
let person = {
    firstName: 'George',
 }

 function printName(greeting) {
  console.log(greeting + this.firstName)
 }

 printName('hello') // Uncaught TypeError: Cannot read property 'firstName' of undefined
Enter fullscreen mode Exit fullscreen mode

After running the code we see that we get an error because JavaScript interpret does not understand object property this.firstName because this value inside a function is set during the execution context. But, how to overcome this issue? JavaScript functions are a special type of objects which contains methods call(), apply() and bind().

call(), apply() and bind()

These methods are inherited by all functions in order to get the value of this in any desired context. The differences between these function methods are that call() method requires parameters as a comma-separated and apply() method in the form of the array list and are executed immediately whereas bind() method can be executed later in any desired context. The code example 5 below shows how we can use these methods and set this in any desired context.

  let person = {
    firstName: 'George',
  }

  function printName(greeting) {
    console.log(greeting + this.firstName);
  }

  printName.call(person, 'Hello') // Hello George
  printName.apply(person, ['Hello there']) // Hello there George
  let executeLater = printName.bind(person)
  executeLater() // George
Enter fullscreen mode Exit fullscreen mode

this with arrow function =>

With ECMAScript 2015 (ES6) arrow function was introduced as a new feature in the world of JavaScript. There are a lot of benefits on using arrow functions which brings shorter function syntax to no need on binding this. With the use of arrow function this is bounded lexically in the enclosing context. Let's see this in action with code example to make it clear.

let greetings = {
  word: 'Hello',
  printGreeting(){
      console.log(this.word)  // Hello
    })
  }
}
Enter fullscreen mode Exit fullscreen mode

If we go back to the previous code example 2 we saw that this inside object refers to the object itself but what if we are required that our greeting to be displayed after 1 second. Then to get the required result we need to modify the code as below

let greetings = {
  word: 'Hello',
  printGreeting(){
    window.setTimeout(function () {
      console.log(this.word) 

    }, 1000) // we can set bind(this)
  }
}

greetings.printGreeting() // undefined
Enter fullscreen mode Exit fullscreen mode

We see that after executing the method printGreeting() we get undefined because the setTimout() function invocation sets this context to the global object. However, here to achieve the result we can use bind() method as we saw previously or we can create a closure just before the setTimeout() function with self=this but we don't need to do this as we can achieve the desired result with the use of arrow function


let greetings = {
  word: 'Hello',
  printGreeting(){
    window.setTimeout(() => {
      console.log(this.word)  
    }, 1000)
  }
}

greetings.printGreeting() // Hello

Enter fullscreen mode Exit fullscreen mode

Now as the result on the console we will get greeting hello because with use of arrow function "this" is bound to the enclosing context and thus our "greetings" object.

That's it! :)

Hopefully, you find interesting this article and will help you in understanding this in JavaScript and its value in a different context.

Top comments (10)

Collapse
 
js2me profile image
Sergey S. Volkov • Edited on

Thanks for good article!
Can you explain more why this
code returns exception?

let person = {
    firstName: 'George',
 }

 function printName(greeting) {
  console.log(greeting + this.firstName)
 }

 printName('hello') // Uncaught TypeError: Cannot read property 'firstName' of undefined
Enter fullscreen mode Exit fullscreen mode

Just context of the printName function refers to window object, as I understand, and because of this output should be helloundefined ?

Collapse
 
donnisnoni profile image
Don Alfons Nisnoni • Edited on

BTW, it would work


let person = {
  firstName: 'George'
}

person.printName = function(greeting) {
  console.log(greeting + " " + this.firstName)
}


printName('Hello') // Hello George
Collapse
 
naimlatifi5 profile image
Naim Latifi Author • Edited on

Hello guys

Thanks for pointing this out and you are both right, by default it should output hello undefined but here I run the code in a strict mode which was my mistake I forgot to mention it(now edited and corrected ). So running this in strict mode it will throw an exception and output with TypeError :)

Collapse
 
dalmo profile image
Dalmo Mendonça

Nice article. Just wanted to point out that while all you said works alright on the frontend, on Node things get more complex.

For example, your very first sample code fails: runkit.com/dalmo3/whatisthis

I used to think it was all the same, then yesterday struggled for a couple of hours before finding out about the module wrapper, exports, global etc.

Collapse
 
naimlatifi5 profile image
Naim Latifi Author

Hello Dalmo,

That's correct in a node.js environment running script code it is essential to have module wrapper with export.

Collapse
 
adam_cyclones profile image
Adam Crockett

Hey Naim, use const πŸ™ƒ

Honourable mention: globalThis

Collapse
 
naimlatifi5 profile image
Naim Latifi Author

Thank you Adam! πŸ˜ƒ

Collapse
 
alexpaper profile image
alexpaper

Thanks for good article! 'This' it is not intuitive.

Collapse
 
naimlatifi5 profile image
Naim Latifi Author

Thank you! πŸ˜ƒ

Visualizing Promises and Async/Await 🀯

async await

☝️ Check out this all-time classic DEV post