# Mastering JavaScript: this, call(), apply() & bind() Explained

1\. What Is `this` in JavaScript?

Rahul is a normal guy. Same person, same face, same brain.

But call him from different places and he responds with a completely different identity.

*   At **home** → Mom calls him *"Munna"*
    
*   At **school** → Teachers call him *"Rahul Kumar"*
    
*   In his **friend circle** → Everyone calls him *"Rocky"*
    

He never changes. Only **who is calling him** changes.

**That is exactly what** `this` **is in JavaScript.**

Case 1 — Global Context (Browser)

In a browser, when you're outside everything no function, no object `this` is the **window** itself.

```javascript
console.log(this); // window
console.log(this === window); // true
```

Rahul is standing in the middle of the city. No home, no school, no friends around. The city itself (`window`) owns him.

## Case 2 — Global Context (Outside Browser / Node.js)

In Node.js, the global object is not `window` it's an **empty module object** `{}` at the top level.

```javascript
console.log(this); // {}  ← empty module object in Node.js
console.log(this === global); // false  ← surprising!
```

Same Rahul, different city. The rules of the city changed.

> Inside a Node.js function though, `this` becomes the `global` object — not `{}`.

## Case 3 — Normal Function (Non-Strict Mode)

Call a plain function with no owner `this` defaults to the **global object**.

```javascript
function whereAmI() {
  console.log(this); // window (browser) or global (Node)
}

whereAmI();
```

Rahul got called but nobody claimed him. So the entire city (`window/global`) becomes his default guardian.

* * *

## Case 4 — Normal Function (Strict Mode)

Add `'use strict'` and everything tightens up. Now `this` is **undefined** inside a plain function call.

```javascript
'use strict';

function whereAmI() {
  console.log(this); // undefined
}

whereAmI();
```

Strict mode says — *"If nobody owns you, you belong to nobody."* Rahul has no identity here. This actually **prevents bugs** because you can't accidentally modify the global object.

## Case 5 — Inside an Object Method

When a function is a property of an object and you call it via that object, `this` is **that object**.

```javascript
const home = {
  name: 'Munna',
  introduce() {
    console.log(`Hi I'm ${this.name}`); // this = home
  }
};

home.introduce(); // Hi I'm Munna
```

Mom called. So inside that context, Rahul is Munna. The object before the dot is always `this`.

## Case 6 — Normal Function *Inside* a Method

This is where most developers get surprised. A regular function nested inside a method **loses** the object's `this`.

```javascript
const home = {
  name: 'Munna',
  introduce() {
    console.log(this.name); // Munna ✅

    function innerFn() {
      console.log(this.name); // undefined ❌
    }

    innerFn(); // nobody called this with 'home'
  }
};

home.introduce();
```

Rahul is Munna when Mom calls him. But the moment a random inner voice speaks — it doesn't belong to Mom anymore. It lost the context.

## Case 7 — Arrow Function (Standalone)

Arrow functions **never have their own** `this`. They look up to their parent scope and borrow whatever `this` is there.

```javascript
const arrowFn = () => {
  console.log(this); // window (borrows from global scope)
};

arrowFn();
```

Rahul as an arrow function has no identity of his own. He just looks at whoever raised him and says *"I'll be whatever you are."*

## Case 8 — Arrow Function *Inside* a Method

This is the **hero move**. Arrow functions fix the problem from Case 6 automatically — because they borrow `this` from the method they're written inside.

```javascript
const home = {
  name: 'Munna',
  introduce() {
    console.log(this.name); // Munna ✅

    const innerArrow = () => {
      console.log(this.name); // Munna ✅ — borrows from introduce()
    };

    innerArrow();
  }
};

home.introduce();
```

The arrow function looks at its parent — `introduce()` — and says *"Your this is my this."* No confusion. Rahul stays Munna throughout.

## Case 9 — Arrow Function as a Method (Don't Do This)

This looks fine but breaks badly.

```javascript
const home = {
  name: 'Munna',
  introduce: () => {
    console.log(this.name); // undefined ❌
  }
};

home.introduce();
```

```javascript

┌──────────────────────────────────────────────
│  Where is 'this'?          │  What does 'this' become? │
├──────────────────────────────────────────────
│  Global (Browser)          │  window                   │
│  Global (Node.js)          │  {}  (module object)      │
│  Normal fn, non-strict     │  window / global          │
│  Normal fn, strict mode    │  undefined                │
│  Object method             │  that object              │
│  Normal fn inside method   │  window / undefined ❌    │
│  Arrow fn (standalone)     │  borrows from parent      │
│  Arrow fn inside method    │  same as method ✅        │
│  Arrow fn as method        │  window / undefined ❌    │
└─────────────────────────────────────────────
```

## `call()` — Borrowing Identity on Demand

* * *

Remember Rahul? He has one `introduce` function. But different worlds want to use it — home, school, friends.

Without `call()`, each world would need to write its own introduce function. That's repetition. That's wasteful.

`call()` says — *"Use this one function, but run it as if it belongs to whoever I say."*

## The Syntax

```javascript
functionName.call(thisArg, arg1, arg2, arg3, ...);
```

*   `thisArg` → who should `this` be inside the function
    
*   `arg1, arg2...` → normal arguments, passed one by one
    
*   runs **immediately**
    

## Case 1 — Basic call(), No Arguments

One function. Three worlds. Zero repetition.

```javascript
function introduce() {
  console.log(`Hi, I'm ${this.name}`);
}

const home         = { name: 'Munna' };
const school       = { name: 'Rahul Kumar' };
const friendCircle = { name: 'Rocky' };

introduce.call(home);
// Hi, I'm Munna

introduce.call(school);
// Hi, I'm Rahul Kumar

introduce.call(friendCircle);
// Hi, I'm Rocky
```

Same function. `this` switches based on what you pass into `call()`.

## Case 2 — call() With Arguments

Now Rahul doesn't just introduce himself — he also tells where he is and what he's doing there.

```javascript
function introduce(place, activity) {
  console.log(`I'm ${this.name}, I'm at ${place} and I'm ${activity}`);
}

const home         = { name: 'Munna' };
const school       = { name: 'Rahul Kumar' };
const friendCircle = { name: 'Rocky' };

introduce.call(home, 'kitchen', 'eating Mom\'s food');
// I'm Munna, I'm at kitchen and I'm eating Mom's food

introduce.call(school, 'classroom', 'solving math');
// I'm Rahul Kumar, I'm at classroom and I'm solving math

introduce.call(friendCircle, 'park', 'playing cricket');
// I'm Rocky, I'm at park and I'm playing cricket
```

Arguments go after `thisArg`, one by one, separated by commas.

## Case 3 — Borrowing a Method from Another Object

This is where `call()` really shines. One object has a method. Another object wants to use it without rewriting it.

```javascript
const home = {
  name: 'Munna',
  introduce() {
    console.log(`Hi, I'm ${this.name} and I belong here`);
  }
};

const school = { name: 'Rahul Kumar' };

// school doesn't have introduce() — but it can borrow it!
home.introduce.call(school);
// Hi, I'm Rahul Kumar and I belong here
```

School borrowed home's `introduce` method. Rahul walked into school and introduced himself as Rahul Kumar — not Munna.

## Case 4 — call() With null

What if you don't care about `this` at all? Pass `null`.

```javascript
function add(a, b) {
  console.log(a + b);
}

add.call(null, 5, 10); // 15
```

`this` becomes the global object (or `undefined` in strict mode). You're essentially just using `call()` to pass arguments which is fine when the function doesn't use `this` at all.

## `apply()` — Same as call(), But Arguments Come in a Box

* * *

Rahul still has the same one function. `apply()` works exactly like `call()` — same idea, same result.

The **only difference?**

*   `call()` → you hand arguments **one by one** like handing someone items individually
    
*   `apply()` → you pack all arguments in an **array** and hand the whole box at once
    

That's it. One difference. Everything else is identical.

## The Syntax

```javascript
functionName.apply(thisArg, [arg1, arg2, arg3, ...]);
```

*   `thisArg` → who should `this` be — same as `call()`
    
*   `[arg1, arg2...]` → arguments packed inside an **array**
    
*   runs **immediately** — same as `call()`
    

## Side by Side — call() vs apply()

```javascript
function introduce(place, activity) {
  console.log(`I'm ${this.name}, at ${place}, ${activity}`);
}

const friendCircle = { name: 'Rocky' };

// call() — arguments one by one
introduce.call(friendCircle, 'park', 'playing cricket');

// apply() — arguments in an array
introduce.apply(friendCircle, ['park', 'playing cricket']);

// Both print exactly the same thing:
// I'm Rocky, at park, playing cricket
```

Same output. Different packaging.

## Case 1 — Basic apply()

```javascript
function introduce(place, activity) {
  console.log(`I'm ${this.name}, I'm at ${place} and I'm ${activity}`);
}

const home         = { name: 'Munna' };
const school       = { name: 'Rahul Kumar' };
const friendCircle = { name: 'Rocky' };

introduce.apply(home, ['kitchen', 'eating Mom\'s food']);
// I'm Munna, I'm at kitchen and I'm eating Mom's food

introduce.apply(school, ['classroom', 'solving math']);
// I'm Rahul Kumar, I'm at classroom and I'm solving math

introduce.apply(friendCircle, ['park', 'playing cricket']);
// I'm Rocky, I'm at park and I'm playing cricket
```

* * *

## Case 2 — Where apply() Wins Over call()

The real power of `apply()` comes when your arguments are **already sitting in an array**. You don't need to unpack them manually.

```javascript
function introduce(place, activity) {
  console.log(`I'm ${this.name}, at ${place}, ${activity}`);
}

const friendCircle = { name: 'Rocky' };

// Arguments already in an array — maybe from an API, a form, anywhere
const details = ['park', 'playing cricket'];

// ❌ With call() — you'd have to unpack manually
introduce.call(friendCircle, details[0], details[1]);

// ✅ With apply() — just pass the array directly
introduce.apply(friendCircle, details);
```

No unpacking. No indexing. Just pass the box.

## Case 3 — apply() With a Dynamic List

Rahul is at school. The subjects he's studying change every day. They come as an array.

```javascript
function studyingToday(sub1, sub2, sub3) {
  console.log(`${this.name} is studying ${sub1}, ${sub2} and ${sub3} today`);
}

const school = { name: 'Rahul Kumar' };

const mondaySubjects  = ['Math', 'Science', 'English'];
const tuesdaySubjects = ['Hindi', 'History', 'Computer'];

studyingToday.apply(school, mondaySubjects);
// Rahul Kumar is studying Math, Science and English today

studyingToday.apply(school, tuesdaySubjects);
// Rahul Kumar is studying Hindi, History and Computer today
```

The array changes. You just pass it in. No rewriting anything.

* * *

## Case 4 — Classic apply() Trick with Math

`apply()` has a famous use case — passing an array to functions that don't normally accept arrays.

```javascript
const marks = [88, 95, 72, 100, 63];

// Math.max doesn't accept arrays directly
console.log(Math.max(marks)); // NaN ❌

// apply() spreads the array into individual arguments
console.log(Math.max.apply(null, marks)); // 100 ✅
console.log(Math.min.apply(null, marks)); // 63  ✅
```

## `bind()` — Save the Identity for Later

* * *

`call()` runs immediately. `apply()` runs immediately.

`bind()` says — *"Don't run yet. Just remember who* `this` *should be, and give me a new function I can use whenever I want."*

Think of it like this —

*   `call()` → Rahul walks into school **right now** and introduces himself
    
*   `apply()` → Rahul walks into school **right now** with a packed bag of things to say
    
*   `bind()` → Rahul gets a **school ID card** made. He can use it anytime he wants to enter school. The identity is locked in permanently.
    

## The Syntax

```javascript
const newFunction = functionName.bind(thisArg, arg1, arg2, ...);

// call it later, whenever you want
newFunction();
```

*   `thisArg` → who `this` should be — locked in permanently
    
*   returns a **brand new function** — does NOT run immediately
    
*   you call that new function whenever you're ready
    

* * *

## Case 1 — Basic bind()

```javascript
function introduce() {
  console.log(`Hi, I'm ${this.name}`);
}

const home         = { name: 'Munna' };
const school       = { name: 'Rahul Kumar' };
const friendCircle = { name: 'Rocky' };

// Create bound versions — not called yet
const introduceMunna  = introduce.bind(home);
const introduceRahul  = introduce.bind(school);
const introduceRocky  = introduce.bind(friendCircle);

// Call them whenever you want
introduceMunna();  // Hi, I'm Munna
introduceRahul();  // Hi, I'm Rahul Kumar
introduceRocky();  // Hi, I'm Rocky
```

Three ID cards made. Each locked to a different identity. Use them anytime.

* * *

## Case 2 — bind() With Arguments

You can pre-fill arguments too — not just `this`.

```javascript
function introduce(place, activity) {
  console.log(`I'm ${this.name}, at ${place}, ${activity}`);
}

const friendCircle = { name: 'Rocky' };

// Lock in both 'this' AND arguments
const rockyAtPark = introduce.bind(friendCircle, 'park', 'playing cricket');

// Call it later — no need to pass arguments again
rockyAtPark();
// I'm Rocky, at park, playing cricket

rockyAtPark();
// I'm Rocky, at park, playing cricket

rockyAtPark();
// I'm Rocky, at park, playing cricket — same every time
```

Once bound, the identity and arguments are frozen. Call it 10 times, same result.

## Case 3 — Partial Application (Pre-fill Some Arguments)

You can bind `this` and only **some** arguments — and fill the rest later when calling.

```javascript
function introduce(place, activity) {
  console.log(`I'm ${this.name}, at ${place}, ${activity}`);
}

const school = { name: 'Rahul Kumar' };

// Lock in 'this' and first argument only
const rahulAtSchool = introduce.bind(school, 'classroom');

// Fill the remaining argument later
rahulAtSchool('solving math');
// I'm Rahul Kumar, at classroom, solving math

rahulAtSchool('giving exam');
// I'm Rahul Kumar, at classroom, giving exam

rahulAtSchool('presenting project');
// I'm Rahul Kumar, at classroom, presenting project
```

Place is locked. Activity changes every time. That flexibility is called **partial application**.

## bind() Returns a New Function (Not a Result)

This is the key thing to remember.

````javascript
function introduce() {
  console.log(`Hi I'm ${this.name}`);
}

const home = { name: 'Munna' };

// call() → runs and returns the result
introduce.call(home); // runs immediately ✅

// bind() → does NOT run, returns a new function
const boundFn = introduce.bind(home);
console.log(boundFn); // [Function: bound introduce]
boundFn(); // now it runs ✅
```

`bind()` gives you a function. You decide when to fire it.
````

## call() vs apply() vs bind()

Same Rahul. Same function. Three different ways to control `this`.

Let's put them all in one place and kill the confusion forever.

## Same Task — Three Ways

````javascript
function introduce(place, activity) {
  console.log(`I'm ${this.name}, at ${place}, ${activity}`);
}

const friendCircle = { name: 'Rocky' };

// call() — args one by one, runs NOW
introduce.call(friendCircle, 'park', 'playing cricket');

// apply() — args in array, runs NOW
introduce.apply(friendCircle, ['park', 'playing cricket']);

// bind() — args one by one, runs LATER
const rockyIntro = introduce.bind(friendCircle, 'park', 'playing cricket');
rockyIntro();

// All three print:
// I'm Rocky, at park, playing cricket
```

Same destination. Three different vehicles.

---

## The Core Difference — One Line Each
```
call()  →  set this + pass args separately  + run immediately
apply() →  set this + pass args as array    + run immediately
bind()  →  set this + pass args separately  + return new function
```

---

## The Deep Comparison Table

┌──────────────────┬───────────────┬──────────
│    Feature       │    call()     │   apply()     │    bind()     
├──────────────────┼─────────────────────────
│ Runs immediately │     ✅ Yes    │    ✅ Yes     │     ❌ No     
│ Returns          │  fn result   │   fn result   │  new function 
│ Arguments format │  one by one  │  in an array  │  one by one   
│ Can reuse?       │     ❌ No    │    ❌ No      │     ✅ Yes    
│ Partial apply?   │     ❌ No    │    ❌ No      │     ✅ Yes   
│ this permanent?  │     ❌ No    │    ❌ No      │     ✅ Yes    
│ Good for         │   borrowing  │  array args   │  callbacks   
│                  │   methods    │  Math tricks  │  event handler
└──────────────────┴───────────────┴───────────
````

## Full Side by Side — Everything Together

```javascript
function introduce(place, activity) {
  console.log(`I'm ${this.name}, at ${place}, ${activity}`);
}

const home         = { name: 'Munna' };
const school       = { name: 'Rahul Kumar' };
const friendCircle = { name: 'Rocky' };

// ── call() ──────────────────────────────────────
introduce.call(home,         'kitchen',   'eating');
introduce.call(school,       'classroom', 'studying');
introduce.call(friendCircle, 'park',      'playing');
// all run immediately ↑

// ── apply() ─────────────────────────────────────
introduce.apply(home,         ['kitchen',   'eating']);
introduce.apply(school,       ['classroom', 'studying']);
introduce.apply(friendCircle, ['park',      'playing']);
// all run immediately ↑

// ── bind() ──────────────────────────────────────
const atHome   = introduce.bind(home,         'kitchen',   'eating');
const atSchool = introduce.bind(school,       'classroom', 'studying');
const atPark   = introduce.bind(friendCircle, 'park',      'playing');

// nothing ran yet ↑ — run them when ready ↓
atHome();    // I'm Munna, at kitchen, eating
atSchool();  // I'm Rahul Kumar, at classroom, studying
atPark();    // I'm Rocky, at park, playing
```

## Conclusion

`this` is not complicated it simply means **who is calling the function** at that moment, just like Rahul responds to a different name depending on where he is. `call()` and `apply()` let you borrow any function and run it immediately with a `this` of your choice the only difference being how you pack the arguments. `bind()` takes it a step further by locking the identity permanently and returning a new function you can carry and use whenever the moment is right. Together, these three give you complete control over context making your code reusable, clean, and free from the classic `this` confusion. Master these and you don't just understand JavaScript better you start thinking in JavaScript
