Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
August 17, 2020 05:04 am GMT

What is 'this' in JavaScript?

Introduction

The 'this' keyword is one such concept that has many layers to it and often a JavaScript newbie can find it overwhelming.

I can assure you that after going through this article, you'll be able to identify what 'this' means based on your function's execution context.

In this article, we will be covering the following topics:

Why does 'this' exist in JavaScript?

Before we get into the details, let us try and understand why 'this' exists in JavaScript. I think it'll be easier to explain it using a code example:

function sayHello(name) {    console.log(`Hello ${name}`);}

The above is a function declaration of 'sayHello' that accepts 'name' as the argument. You'll not be able to say what will display on the console unless the function is invoked and a value is passed to the 'name' argument is passed to the function.

sayHello('Skay');//Output -> Hello Skay

When the function 'sayHello' is invoked with 'Skay', the output 'Hello Skay' displays on the console.

You can think of 'this' keyword behaviour to be very similar that of the above function argument example. The value of 'this' keyword will vary based on how the function is invoked.

Simply stated, the 'this' keyword exists in order to allow the user to decide which object should be focal when invoking a function or a method.

Implicit Binding

Implicit Binding rule states that in order to figure out what 'this' keyword references, first, look to the left of the dot of the function that is invoked.

Let us look at a simple example to figure out what the above means:

const user = {  name: 'Skay',  age: 38,  sayHello: function () {    console.log(`Hello ${this.name}`); // The 'this' keyword references the 'user' object  },};//Note: Implicit Binding Rule//To the left of the function call 'sayHello()' the user object is present//Hence 'this' in this function invocation refers to the 'user' objectconsole.log(user.sayHello());//Output -> Hello Skay

Thing to Note:

  • The 'user' object contains the 'sayHello' function which references the 'this' keyword.
  • To the left of the function call 'sayHello' function is the user object and by implicit biding rule, the 'this' keyword references the 'user' object.
${this.name} -> gets translated to -> ${user.name}

So, what happens when there isn't any dot to the left of the function call? That brings us to the next concept, the explicit binding.

Explicit Binding

Let us take the above example and move the function 'sayHello' out of the 'user' object.

const user = {  name: 'Skay',  age: 38,};//The function sayHello() moved out of the user objectconst sayHello = function () {  console.log(`Hello ${this.name}`);};

Now, how do we bind the 'user' object to the 'sayHello' function? We have the 'call' function to our rescue.

Call

'call' is a property of every function and the first argument you pass to 'call' will reference 'this' keyword within the function through Explicit binding.

//Using 'call' keyword, we are passing the 'user' object as an argument.//This explicitly binds the 'user' object to the 'this' keywordsayHello.call(user);

As you can see from the above code, the 'user' object is explicitly bound to the 'sayHello' function using the 'call' property.

Apply

Let us take another example of the below function 'polyglot' that accepts arguments language1 and language2.

const user = {  name: 'Skay',  age: 38,};const polyglot = function (language1, language2) {  console.log(    `Hello, I'm ${this.name} and I know ${language1} and ${language2}`  );};

Now, we know that using the 'call' property, we can bind the user object to the function explicitly and pass the arguments as shown below.

polyglot.call(user, 'JavaScript', 'Java');//Output -> Hello, I'm Skay and I know JavaScript and Java

Now, the 'apply' keyword gives you the flexibility to send multiple parameters using an array instead of individual values.

//Define the array that needs to be passed as arguments to the functionconst languages = ['JavaScript', 'Java'];//Use the apply keyword to explicitly bind the user object & pass the languages arraypolyglot.apply(user, languages);//Output -> Hello, I'm Skay and I know JavaScript and Java

In other words, 'apply' is exactly same as 'bind' except for the fact that it provides you the flexibility to pass a single array which will spread each element of the array as arguments to the function.

Bind

So far, we have seen both 'call' and 'apply' keywords under explicit binding. The last one is 'bind', which is again exactly the same as 'call', but it returns a function that can be invoked at a later time than running it right away.

Let us look at the first example and find out how 'bind' keyword works with it.

const user = {  name: 'Skay',  age: 38,};const sayHello = function () {  console.log(`Hello ${this.name}`);};//The 'bind' keyword returns a function instead of invoking the function immediatelyconst laterFn = sayHello.bind(user);//The function is invoked to display the greeting on the consolelaterFn(); //Output -> Hello Skay

That concludes all the various ways of how to identify 'this' keyword with explicitly binding.

new Binding

In JavaScript, you can define a constructor function through which other objects can be created. Let us look at the below code example.

//Fruit is a constructor which accepts name and color as arguments//Whenever the function 'Fruit' is invoked using the new keyword a new object is created//The new object created will reference the 'this' keywordconst Fruit = function (name, color) {  this.name = name;  this.color = color;  this.greet = function () {    console.log(`Hello, I'm ${this.name} and my color is ${this.color}`);  };};//Apple object will be created with the this.name & this.color referencing Apple & Redconst apple = new Fruit('Apple', 'Red');//Banana Object will be created with the this.name & this.color referencing Banana & Yellowconst banana = new Fruit('Banana', 'Yellow');//Greet function will be invoked with 'apple' referenceapple.greet(); //Output -> Hello, I'm Apple and my color is Red//Greet function will be invoked with 'banana' referencebanana.greet(); //Output -> Hello, I'm Banana and my color is Yellow

Things to Note:

  • When the constructor function 'Fruit' is invoked with the 'new' keyword, a new object will be created.
  • The 'this' keyword will naturally reference the newly created object during assignment.

Lexical Binding

Lexical binding is probably easier explained through a code example.

//A Constructor Function that accepts 'name' & 'hobby' arrayconst Person = function (name, hobbies) {  this.name = name;  this.hobbies = hobbies;  this.display = function () {        //hobbies array iterated through the map function    this.hobbies.map(function (hobby) {            //Inside this anonymous function, the 'this.name' cannot be found            //Reason -> A new scope gets created within anonymous function      console.log(`My name is ${this.name} & my hobby is ${hobby}`);    });  };};const hobbies = ['Sports', 'Music'];const me = new Person('Skay', hobbies);me.display();/** Output * My name is  & my hobby is Sports * My name is  & my hobby is Music */

Let us look at the above code example in detail:

  • The 'Person' is a constructor function that accepts both 'name' and 'hobbies' array.
  • We are invoking the constructor function with the name 'Skay' and the 'hobbies' array 'Sports' and 'Music'.
  • When the 'display' function is invoked, the hobbies.map function is invoked.
  • There's an inner anonymous function within the hobbies.map function which creates it's own scope and hence when '${this.name}' is encountered, it tries to search for 'name' within the new context and does not find it.
  • Hence the output does not print the 'name' field.

Ideally, the expectation would have been lookup to the parent scope and find the 'name' variable within the Person function. This was addressed when ES6 arrow function was created.

However, we can still address this problem by using the 'bind' keyword as shown in the code example below.

Using bind

The example is exactly the same as above, but we are using the 'bind' keyword to explicitly bind the 'this' keyword to the anonymous function. If you run the function, you should see the 'this.name' would be properly referenced and the output printing the name as 'Skay'.

const Person = function (name, hobbies) {  this.name = name;  this.hobbies = hobbies;  this.display = function () {    this.hobbies.map(      function (hobby) {        console.log(`My name is ${this.name} & my hobby is ${hobby}`);            //By 'explicit' binding the 'this' object the 'this.name' will be referenced      }.bind(this)    );  };};const hobbies = ['Sports', 'Music'];const me = new Person('Skay', hobbies);me.display();/** Output * My name is Skay & my hobby is Sports * My name is Skay & my hobby is Music */

ES6 - Arrow Function

The same code can be simply addressed by using an Arrow Function. This is recommended and preferred and is compatible with all modern browsers.

We just removed the 'function' keyword and replaced it with the 'arrow' symbol to make it an arrow function. If you like to read more, here's a detailed article on arrow functions.

const Person = function (name, hobbies) {  this.name = name;  this.hobbies = hobbies;  this.display = function () {    this.hobbies.map((hobby) => {      console.log(`My name is ${this.name} & my hobby is ${hobby}`);    });  };};const hobbies = ['Sports', 'Music'];const me = new Person('Skay', hobbies);me.display();/** Output * My name is Skay & my hobby is Sports * My name is Skay & my hobby is Music */

Window Binding

Finally, we come to the window binding which is probably also referred to as the global context.

function displayFruit() {  console.log(`Hello ${this.fruit}`);}displayFruit();//Output -> Hello Undefined

In the above code example, there's no dot operator and hence no implicit binding happened. Also, since call, apply, bind were used to explicitly bind the function with an object, the 'this' keyword get bound to the global object which is the 'window' object.

If you define 'fruit' variable to the window object and run the above code, it'll print the name of the fruit as shown below.

function displayFruit() {  console.log(`Hello ${this.fruit}`);}window.fruit = 'Peach';displayFruit();//Output -> Hello Peach

Strict Mode

If you have the strict mode enabled, then the JavaScript will NOT allow the reference of the 'this' keyword to default to the window object. It will just keep this as undefined as shown in the code example below.

'use strict'function displayFruit() {  console.log(`Hello ${this.fruit}`);}window.fruit = 'Peach';displayFruit();//Output -> Hello undefined

Conclusion

That's it folks! We've covered all that's there to find out how to identify the 'this' object in JavaScript.

So, whenever you see a 'this' keyword inside a function, then you'll apply the following rules:

  1. Check where the function was invoked.
  2. If there is an object to the left of the dot, then, that's what the this keyword is referencing. If not, continue to the next step.
  3. If the function was invoked with a call, apply, or bind keword, then itll explicitly state what object the this keyword is referencing to. If not, continue to the next step.
  4. Was the function invoked using the new keyword? If so, the this keyword is referencing the newly created object. If not, continue to the next step.
  5. Is this inside of an arrow function? If so, its reference may be found lexically in the enclosing (parent) scope. If not, continue to the next step.
  6. If you are in 'strict mode', then this keyword is undefined. If not, continue to next step.
  7. The this keyword defaulted to the global window object.

Hope you enjoyed this article! Do let me know your comments and feedback on the same.

You might also be interested in:


Original Link: https://dev.to/skaytech/what-is-this-in-javascript-3d3i

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To