All about "this" and "this" manipulation in Javascript
Published: 2023-12-03 15:52:23

Earlier I found it a bit tricky to understand the concept of `this` keyword, till I found the right way to understand it and the magic word here is **the context**.

## So what is exactly **`this`**?

In JavaScript, the `this` keyword is a special keyword that refers to the current instance of an object or the **context** in which a function is executed. The value of this is determined by how a function is called or how an object is accessed.

and `this` is affected by the context as follows:

### 1- Global Context:

When `this` is used outside of any function or object, it refers to the global object. In a web browser, the global object is `window`.

```javascript 
console.log(this); // Points to the global object (e.g., window in a browser)
```

### 2- Function/Method Context:

Inside a function, the value of `this` depends on how the function is called. when a function is a method of an object, it refers to the object that the method is called on.

```javascript 
function exampleFunction() {
  console.log(this);
}

exampleFunction(); // Points to the global object (e.g., window in a browser)

const myObject = {
  myMethod: function() {
    console.log(this);
  }
};

myObject.myMethod(); // Points to myObject
```

### 3- Constructor Context:

When a function is used as a constructor with the new keyword, this refers to the newly created instance of the object.

```javascript 
function MyClass() {
  this.property = 'value';
}

const myInstance = new MyClass();
console.log(myInstance.property); // 'value'
```

```javascript 
class MyClass {
  constructor(name) {
    // 'this' refers to the instance being created
    this.name = name;
  }

  sayHello() {
    console.log(`Hello, my name is ${this.name}`);
  }
}

// Creating an instance of MyClass
const myInstance = new MyClass("John");

// Calling a method using 'this'
myInstance.sayHello(); // Output: Hello, my name is John
```

### 4- Event Handler Context:
In event handlers, this often refers to the element that triggered the event.

```javascript 
document.getElementById('myButton').addEventListener('click', function() {
  console.log(this); // Points to the clicked button element
});
```


# `this` with arrow functions:
It's important to note that arrow functions behave differently regarding `this`. They do not have their own `this` context and inherit it from the enclosing scope. 

In other words `this` in the arrow function refers to the object where that function was first defined.

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

// Arrow function
const arrowFunction = () => {
  console.log(this);
};

const obj = {
  method1: regularFunction,
  method2: arrowFunction
};

obj.method1(); // `this` refers to obj (method1 is called as a method of obj)
obj.method2(); // `this` refers to the enclosing scope (arrowFunction was created in the global scope)
```

In the example above:

- When **`method1`** (which is a regular function) is called, **`this`** refers to the **`obj`** object because it is called as a method of **`obj`**.
- When **`method2`** (which is an arrow function) is called, **`this`** does not have its own context and refers to the **`this`** value of the enclosing scope at the time the arrow function was created. In this case, since **`arrowFunction`** is defined in the global scope, **`this`** refers to the global object (e.g., **`window`** in a browser environment).

# **`this`** manipulation:

in order to manipulate and change the context of `this` we can use `bind`, `call`, and `apply` methods.

Here's an explanation of each, along with examples:

### 1- bind:
The `bind` method creates a new function that, when called, has its `this` keyword set to a specific object.

```javascript 
const john = {
  name: 'John',
  sayHello: function() {
    console.log(`Hello, ${this.name}!`);
  }
};
const alex = {
  name: 'Alex',
  sayHello: function() {
    console.log(`Hello, ${this.name}!`);
  }
};
const greetJohn = john.sayHello.bind(john);
const greetAlex = john.sayHello.bind(alex);
greetJohn(); // Outputs: Hello, John!
greetAlex(); // Outputs: Hello, Alex!
```

### 2- call:

The `call` method invokes a function with a specified `this` value and individual arguments.

```javascript 
function introduce(age, job) {
  console.log(`Hi, I'm ${this.name}. I'm ${age} years old and work as a ${job}.`);
}

const person = {
  name: 'Alice'
};

introduce.call(person, 25, 'developer');
// Outputs: Hi, I'm Alice. I'm 25 years old and work as a developer.
```
Here, `call` is used to invoke the `introduce` function with the person object as the `this` value and additional arguments.

### 2- apply:

The `apply` method is similar to `call`, but it takes an array of arguments instead of individual arguments.

```javascript 
function introduce(age, job) {
  console.log(`Hi, I'm ${this.name}. I'm ${age} years old and work as a ${job}.`);
}

const person = {
  name: 'Bob'
};

introduce.apply(person, [30, 'engineer']);
// Outputs: Hi, I'm Bob. I'm 30 years old and work as an engineer.
```

Here, **`apply`** is used to invoke the **`introduce`** function with the **`person`** object as the **`this`** value and an array of arguments.

In summary:

- Use **`bind`** when you want to create a new function with a fixed **`this`** value.
- Use **`call`** when you want to invoke a function with a specific **`this`** value and individual arguments.
- Use **`apply`** when you want to invoke a function with a specific **`this`** value and an array of arguments.

That's all, happy coding :)