JavaScript ‘this’ keyword’s binding rules
Tags: javascript, frontend, beginners, webdev
Published: 2023-09-17 22:37:03

**_The ‘this’ keyword in JavaScript can be perplexing for many developers, and I, too, struggled with it for quite some time. If you’re one of those developers eager to grasp how ‘this’ works, you’re in the right place. By the end of this article, you’ll have a clear understanding of ‘this’. So, let’s get started!_**

## Introduction

**What is the ‘this’ keyword in JavaScript?**

In JavaScript, the ‘**this**’ keyword refers to the object being executed in the current context, in other words, The ‘**this**’ keyword refers to different objects depending on how it is used.

**What does the ‘this’ keyword allow you to do?**

The ‘**this**’ keyword allows you to reuse functions with different contexts. In other words, it enables you to determine or specify which object should be the focus of the context when invoking a function or a method. For example, when you have multiple objects with the same properties and a single function, ‘**this**’ allows that function to work with all of your objects.

## Binding rules

### 1. Global object binding

**A. ‘this’ In the global context**

If the ‘**this**’ keyword is not inside a function or an object, it refers to the window(global) object.

**Example**:

```
console.log(this);
console.log(this === window);
window.firstName = "Badreddine";
console.log(this.firstName);
```
As mentioned earlier, in the global context, ‘**this**’ refers to the window(global) object. In the example above, the first line logs the window object, and the second line logs true.

To illustrate further, we create a variable “firstName” on the window object and assign it the value “Badreddine”. Since ‘**this**’ refers to the window (global) object, the fourth line will log the value “Badreddine”, which is the value of the “firstName” property on the global (window) object.

**Output**:

![console log of the code above](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/71qaki97l3mdleomw2py.png)

And it’s the same output whether it’s in strict mode or default mode.

**B. ‘this’ in a regular function**

‘**this**’ inside a regular function, when ‘**this**’ is used without any specific context, it still refers to the window object.

**Example1**:

```
function regularFunction() {
    console.log(this);
}

regularFunction();
```
**Output**:

![console log of the code above](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kbd7l8s0tp84u0i3fqoe.png)

In strict mode, ‘**this**’ in a regular function is undefined.

**Example2**:

```
"use strict";
function regularFunction() {
    console.log(this);
}

regularFunction();
```
**Output**:

![console log of the code above](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bwpihuqwtgp3i55bbjw6.png)

**Example3**:

```
var firstName = "Badreddine";
function regularFunction() {
   const firstName = "Badr";
   console.log(firstName);
   console.log(this.firstName);
}

regularFunction();
```
In the example above we declare two variables with the same name, one inside the function and another one outside, what would be the output?

**Output**:

![console log of the code above](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cid7us4nc0t8jfcn4unh.png)

The first log (fourth line) will output “Badr”. However, the second log (fifth line) will output “Badreddine”, and that’s because ‘**this**’ in regular function refers to the window(global) object as we said earlier.

Just one thing to add: if the outside “firstName” variable was declared with `let` or `const`, the output would be undefined, as shown below.

**Example4**:

```
const firstName = "Badreddine";
function regularFunction() {
   const firstName = "Badr";
   console.log(firstName);
   console.log(this.firstName);
}

regularFunction();
```
**Output**:

![console log of the code above](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rj6s72ub13y4aooq5d1z.png)

And that’s because variables declared with `var` are added as properties of the global (window) object, unlike variables declared with `let` and `const`, which are not.

### 2. Implicit Binding
Implicit binding occurs when you invoke a function using dot notation, in those cases, we need to check the object adjacent to the method at invocation time. In simple words look at the function invocation, the object on its left is what ‘**this**’ refers to.

**Example1**:

```
const infos = {
   firstName: "Badreddine",
   job: "Frontend Developer",
   msg() {
      console.log(`Hi my name is ${this.firstName}, I'm a ${this.job}`);
   },
};

infos.msg();
```
In the example above we create an object “infos” with two properties and one method, then we invoke the “msg” method using `infos.msg()`.

**Output**:

![console log of the code above](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/55aec9k75kgc2p5nhs8n.png)

The output is as expected, ‘**this**’ refers to the object on the left of the function invocation(“infos”).

**Example2**:

```
function infosMsg(obj) {
   obj.msg = function () {
      console.log(`Hi, my name is ${this.name}, I'm a ${this.job}`);
   };
}

const badreddine = {
   name: "Badreddine",
   job: "Frontend Developer",
};

const ali = {
   name: "Ali",
   job: "Backend Developer",
};

infosMsg(badreddine);
infosMsg(ali);

badreddine.msg();
ali.msg();
```
In the example above we create a function “infoMsg” that takes one parameter, “obj”. Inside the function, we add a new method called “msg” to the “obj” parameter.

Then, we create two objects, “badreddine” and “ali”, and called the “infoMsg” function for both objects.

Finally, we invoke the “msg” method on both objects.

**Output**:

![console log of the code above](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kw3mdjsy2p7cyjr2puw6.png)

The output is as expected: when the method is called with the “badreddine object, ‘**this**’ refers to the “badreddine” object, and when it’s called with the “ali” object, it refers to the “ali” object.

### 3. Explicit Binding
Explicit binding occurs when we use `call()`, `apply()`, and `bind()` methods on a function. It’s called explicit because we explicitly specify the value of ‘**this**’.

The three methods are predefined JavaScript methods used to control the value of ‘**this**’, and they can accept additional arguments alongside the context(value of ‘**this**’) as the first argument.

#### A. call() method

The `call()` method can take ‘**this**’ as the first argument, followed by an unlimited number of arguments.

**Example**:

```
const infos = function (techOne, techTwo, techThre) {
   console.log(
      `Hi, my name is ${this.name}, I'm a ${this.job}, I use ${techOne}, ${techTwo} and ${techThre}`
   );
};

const me = {
   name: "Badreddine",
   job: "Frontend Developer",
};

const technologies = ["React", "TypeScript", "Tailwind"];

infos.call(me, technologies[0], technologies[1], technologies[2]);
```
In the example above we create a function “infos” which takes parameters, an object “me” and an array “technologies”.

We use the `call()` method on the “infos” function to invoke it. The `call()` method takes the “me” object as its first argument, which sets the value of ‘**this**’ inside the “infos” function to the “me” object. The subsequent arguments (technologies[0], technologies[1], and technologies[2]) are passed as arguments to the “infos” function.

Inside the “infos” function, “this.name” and “this.job” now refer to the properties of the “me” object

**Output**:

![console log of the code above](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wohug1orl2qqbxbqtcfy.png)

#### B. apply() method

The `apply()` method can take a ‘**this**’ argument followed by an array of unlimited elements.

The difference between `call()` and `apply()` methods is how arguments are passed to the function. `call()` accepts arguments as individual parameters, while `apply()` accepts arguments as an array.

**Example**:

```
const infos = function (techOne, techTwo, techThre) {
   console.log(
      `Hi, my name is ${this.name}, I'm a ${this.job}, I use ${techOne}, ${techTwo} and ${techThre}`
   );
};

const me = {
   name: "Badreddine",
   job: "Frontend Developer",
};

const technologies = ["React", "TypeScript", "Tailwind"];

infos.apply(me, technologies);
```
In the example above we create a function “infos” which takes parameters, an object “me” and an array “technologies”.

We use the `apply()` method on the “infos” function to invoke it. The `apply()` method takes “me” object as its first argument, which sets the value of ‘**this**’ inside the “infos” function to the “me” object. The second argument (technologies) is an array that will be spread as arguments to the “infos” function.

Inside the “infos” function, “this.name” and “this.job” now refer to the properties of the ‘me’ object.

**Output**:

![console log of the code above](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2qqy9w6ejeeqg8a1ba2q.png)

#### C. bind() method

The `bind()` method can take ‘**this**’ as the first argument, followed by an unlimited number of arguments.

The difference between `call()` and `bind()`, is that `call()` immediately invokes the function, while `bind()` returns a new function which you can call it later.

**Example**:

```
const infos = function (techOne, techTwo, techThre) {
   console.log(
      `Hi, my name is ${this.name}, I'm a ${this.job}, I use ${techOne}, ${techTwo} and ${techThre}`
   );
};

const me = {
   name: "Badreddine",
   job: "Frontend Developer",
};

const technologies = ["React", "TypeScript", "Tailwind"];

const newFunc = infos.bind(me, technologies[0], technologies[1], technologies[2]);
newFunc();
```
In the example above we create a function “infos” which takes parameters, an object “me” and an array “technologies”.

Then we create a new function “newFunc” and initialize it with the returned function(the `bind()` method on the “infos” function). The bind() method takes “me” object as its first argument, which sets the value of ‘**this**’ inside the “infos” function to the “me” object. The subsequent arguments (technologies[0], technologies[1], and technologies[2]) are passed as arguments to the “infos” function.

Finally, we invoke the “newFunc” fonction

Inside the “infos” function, “this.name” and “this.job” now refer to the properties of the “me” object

**Output**:

![console log of the code above](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0dpcczm4i7w6nf4ii1v4.png)

### 4. The new keyword
When you call a function with the new keyword in JavaScript, a new instance of the constructor is created, and ‘**this**’ keyword within the constructor function refers to the instance being created. Additionally, any properties and/or methods defined within the constructor will be assigned to that newly created instance.

#### A. function constructor

A function constructor is a regular JavaScript function that is used to create objects.

**Example**:

```
function Developer(name, job) {
   this.name = name;
   this.job = job;
   this.msg = function () {
      console.log(`Hi my name is ${this.name}, I'm a ${this.job}`);
   };
}

let me = new Developer("Badreddine", "Frontend Developer");
me.msg();
```
In the example above we define a constructor function called “Developer” that takes two parameters “name” and “job”.

Within the constructor, we use the ‘**this**’ keyword to assign values to the properties of the object being created (“this.name” and “this.job”). This allows us to initialize each instance of Developer with specific values for name and job.

Additionally, we define a method named “msg” within the constructor.

Then we create a new instance of the Developer object by calling `new Developer(“Badreddine”, “Frontend Developer”)`. This instance is stored in the variable “me”.

Finally, we invoke the “msg” method on the “me” object.

**Output**:

![console log of the code above](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q6wlc9116egnuy74p7po.png)

#### B. class

a class in JavaScript is essentially a syntactic way of defining constructor functions introduced in ES6.

**Example**:

```
class Developer {
   constructor(name, job) {
      this.name = name;
      this.job = job;
      this.msg = function () {
         console.log(`Hi my name is ${this.name}, I'm a ${this.job}`);
      };
   }
}

let me = new Developer("Badreddine", "Frontend Developer");
me.msg();
```
In the example above we define a class called “Developer” using the “class” keyword. This class serves as a blueprint for creating developer objects. Inside the Developer class, we define a constructor method using the “constructor” keyword. The constructor method takes two parameters, “name” and “job”, representing the name and job title of a developer, and it is automatically called when you create a new instance of the class.

Within the constructor method, we use the ‘**this**’ keyword to assign the provided name and job values to the object being created.

Additionally, we define a method called “msg” within the constructor method.

we create a new instance of the Developer class by calling `new Developer(“Badreddine”, “Frontend Developer”)`. This instance is stored in the variable me.

Finally, you invoke the “msg” method on the “me” object.

**Output**:

![console log of the code above](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2igeyuci5qgidaden1ht.png)

### 5. Arrow Functions
The arrow function is another way to create functions introduced in ES6. When you use ‘**this**’ with an arrow function, it would refer to the surrounding lexical context and that’s because it does not have its own context. The lexical context could be a parent function, a global context, or any enclosing scope where the arrow function is defined.

**Example1**:

```
const infos = {
   firstName: "Badreddine",
   msg: () => {
      console.log(`Hi, my name is ${this.firstName}`);
      console.log(this);
   },
};

infos.msg();
```
In the example above we create an object “infos” with a “firstName” property set to the string “Badreddine”.

Inside the “infos” object, we define a method “msg” using an arrow function syntax.

We call the “msg” method on the “infos” object.

**Output**:

![console log of the code above](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/delwjsst7sl7956eq478.png)

Now, here’s what happens when we run this code:

The first log attempts to access “this.firstName”. However, since arrow functions inherit the ‘**this**’ value from their surrounding lexical scope, and there is no outer function or scope that defines ‘**this**’, ‘**this**’ refers to the global object (window). Therefore, “this.firstName” will likely be undefined.

The second log logs the ‘**this**’ object, which will typically be the global object (window).

**Example2**:

```
const infos = {
    firstName: "Badreddine",
    msg() {
       let logMsg = () => {
          console.log(`Hi, my name is ${this.firstName}`);
          console.log(this);
       };
       logMsg();
    },
 };

 infos.msg();
```
In the example above we create an object named “infos” with a “firstName” property set to the string “Badreddine”.

Inside the “infos” object, we define a method “msg”.

Inside the “msg” method, we define a nested function called “logMsg” using the arrow function syntax and we call it.

Finally, we call the “msg” method on the “infos” object.

**Output**:

![console log of the code above](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cmfo83zha06siygiccj0.png)

Now, here’s what happens when we run this code:

The “logMsg” arrow function is called within the “msg” method.

Inside the “logMsg” function:

The first log attempts to access “this.firstName”. Since arrow functions inherit the ‘**this**’ value from their surrounding lexical scope (in this case, the “msg” method), “this.firstName” refers to the “firstName” property of the “infos” object.

The second log logs the ‘**this**’ object. Again, ‘**this**’ inherits the value from the surrounding lexical scope, which is the “msg” method. Therefore, it refers to the “infos” object.

## Conclusion

- Recap of key points about ‘**this**’ in JavaScript.

- Alone, in a global context ‘**this**’ refers to the global(window) object, whether it’s in strict mode or default mode.

- In a regular function when ‘**this**’ is used without any specific context, in default mode, ‘**this**’ refers to the global(window)object, but in strict mode it’s undefined.

- In the implicit binding cases, ‘**this**’ refers to the object on the left side of the function at invocation time.

- In the explicit binding cases, ‘**this**’ refers to the value you explicitly specify.

- In an arrow function, ‘**this**’ does not have its own context, so it would refer to the surrounding lexical context.