DEV Community

Cover image for Why "this" Betrays You & How call/apply/bind Save Your Life – The Complete Story
MUHAMMAD USMAN AWAN
MUHAMMAD USMAN AWAN

Posted on

Why "this" Betrays You & How call/apply/bind Save Your Life – The Complete Story

πŸ”₯ THE ULTIMATE JS LESSON β€” this Keyword (Browser & Node)

Greetings, fellow developers! Today, we dive into a comprehensive exploration of the this keyword and the powerful call / apply / bind methods.

πŸš€ Repo: javascript-complete-mastery


πŸš€ 1. What is this in JavaScript?

this depends entirely on HOW a function is called, not where it is written.


🧠 2. 5 Core Rules of this (Browser + Node)


Rule 1 β€” Global Context

Browser

console.log(this); 
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ window

Node

console.log(this);
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ {}


Rule 2 β€” Function Context

Non-strict mode

function test() {
  console.log(this);
}
test();
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ Browser β†’ window
πŸ‘‰ Node β†’ global

Strict mode

"use strict";
function test() {
  console.log(this);
}
test();
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ undefined


Rule 3 β€” Method Call (Object Method)

this = object before dot

const user = {
  name: "Usman",
  greet() {
    console.log(this.name);
  }
};

user.greet(); 
Enter fullscreen mode Exit fullscreen mode

βœ” "Usman"


Rule 4 β€” Constructor / Class

function Person(name) {
  this.name = name;
}

const p = new Person("Usman");
console.log(p.name);
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ this refers to the new object


Rule 5 β€” Arrow Functions (NO own this)

const obj = {
  value: 10,
  test: () => {
    console.log(this);
  }
};

obj.test();
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ Browser: window
πŸ‘‰ Node: {}


πŸ”₯ Browser vs Node Quick Comparison

Scenario Browser Node
Global context window {}
Function (non strict) window global
Function (strict) undefined undefined
Method Object Object
Arrow Parent scope Parent scope

⚑ 3. Deep Examples (Tricky)


Example β€” Losing this

const user = {
  name: "Usman",
  greet() {
    console.log(this.name);
  }
};

const x = user.greet;
x(); 
Enter fullscreen mode Exit fullscreen mode

❌ undefined


Example β€” Fix with bind

const x = user.greet.bind(user);
x();
Enter fullscreen mode Exit fullscreen mode

βœ” "Usman"


Arrow inside methods

const user = {
  name: "Usman",
  greet: function () {
    setTimeout(() => {
      console.log(this.name);
    }, 100);
  }
};

user.greet();
Enter fullscreen mode Exit fullscreen mode

βœ” "Usman"


Arrow in object (incorrect assumption)

const obj = {
  a: 10,
  print: () => console.log(this.a)
};

obj.print();
Enter fullscreen mode Exit fullscreen mode

❌ undefined


🧩 Event Listeners

Normal function

button.addEventListener("click", function() {
  console.log(this); 
});
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ this = button element

Arrow function

button.addEventListener("click", () => {
  console.log(this); 
});
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ this = window


πŸ“¦ Node.js Module Wrapper

(function(exports, require, module, __filename, __dirname) {
   // code
})();
Enter fullscreen mode Exit fullscreen mode

So:

console.log(this); // {}
Enter fullscreen mode Exit fullscreen mode

πŸ“ Summary Cheat Sheet

this = depends on how the function is called
Enter fullscreen mode Exit fullscreen mode

Browser

  • Global β†’ window
  • Function non strict β†’ window
  • Strict β†’ undefined
  • Method β†’ object
  • Arrow β†’ parent

Node

  • Global β†’ {}
  • Function non strict β†’ global
  • Strict β†’ undefined
  • Method β†’ object
  • Arrow β†’ parent

πŸ‹οΈβ€β™‚οΈ PRACTICE SECTION


βœ… EASY (3)


Problem 1

console.log(this);
Enter fullscreen mode Exit fullscreen mode

βœ” Browser β†’ window
βœ” Node β†’ {}


Problem 2

function test() {
  console.log(this);
}
test();
Enter fullscreen mode Exit fullscreen mode

βœ” Browser β†’ window
βœ” Node β†’ global


Problem 3

const obj = {
  a: 5,
  show() {
    console.log(this.a);
  }
};

obj.show();
Enter fullscreen mode Exit fullscreen mode

βœ” 5


⚑ MEDIUM (3)


Problem 1

const obj = {
  a: 10,
  b: () => console.log(this.a)
};

obj.b();
Enter fullscreen mode Exit fullscreen mode

βœ” undefined


Problem 2

"use strict";

function x() {
  console.log(this);
}

x();
Enter fullscreen mode Exit fullscreen mode

βœ” undefined


Problem 3

const user = {
  name: "Ali",
  greet() {
    setTimeout(function() {
      console.log(this.name);
    }, 0);
  }
};

user.greet();
Enter fullscreen mode Exit fullscreen mode

βœ” undefined


πŸ”₯ HARD (4)


Problem 1

const obj = {
  name: "Usman",
  greet() {
    return () => console.log(this.name);
  }
};

const x = obj.greet();
x();
Enter fullscreen mode Exit fullscreen mode

βœ” "Usman"


Problem 2

class A {
  constructor() {
    this.num = 100;
  }

  show() {
    console.log(this.num);
  }
}

const a = new A();
const s = a.show;
s();
Enter fullscreen mode Exit fullscreen mode

βœ” undefined


Problem 3

const obj = {
  x: 15,
  y: {
    z: function() {
      console.log(this.x);
    }
  }
};

obj.y.z();
Enter fullscreen mode Exit fullscreen mode

βœ” undefined


Problem 4

let a = {
  value: 50,
  print: function() {
    (function() {
      console.log(this.value);
    })();
  }
};

a.print();
Enter fullscreen mode Exit fullscreen mode

βœ” undefined


πŸš€ THE ULTIMATE JS LESSON β€” call(), apply(), bind()

JavaScript gives us three powerful methods to manually control the value of this inside a function.
These are essential for interview questions, real-world bug fixing, and writing professional code.


πŸ”₯ 1. Why do we need call/apply/bind?

Because sometimes, a function loses its this:

function greet() {
  console.log(this.name);
}

const user = { name: "Usman" };

greet();  // ❌ undefined
Enter fullscreen mode Exit fullscreen mode

We want to run greet with this = user.

That’s where these methods come in.


🧠 2. call() β€” calls the function immediately

func.call(thisValue, arg1, arg2, ...)
Enter fullscreen mode Exit fullscreen mode

Example

function greet(age) {
  console.log(this.name, age);
}

const user = { name: "Usman" };

greet.call(user, 22);
Enter fullscreen mode Exit fullscreen mode

βœ” Sets this = user
βœ” Executes immediately
βœ” Arguments passed one-by-one


🧠 3. apply() β€” same as call, but arguments in an array

func.apply(thisValue, [arg1, arg2, ...])
Enter fullscreen mode Exit fullscreen mode

Example

greet.apply(user, [22]);
Enter fullscreen mode Exit fullscreen mode

βœ” Same output
βœ” Just a different argument format


🧠 4. bind() β€” returns a NEW function with fixed this

const newFn = func.bind(thisValue, arg1, arg2);
Enter fullscreen mode Exit fullscreen mode

Example

const greetUser = greet.bind(user, 22);
greetUser();
Enter fullscreen mode Exit fullscreen mode

βœ” Does NOT run immediately
βœ” Creates a new function with permanent this


πŸ”‘ 5. The Three in One Line

call  β†’ call immediately (args individually)
apply β†’ call immediately (args in array)
bind  β†’ return new function (does NOT run)
Enter fullscreen mode Exit fullscreen mode

πŸ“¦ 6. Real-world Uses

βœ” Borrowing methods

let obj1 = { name: "Ali" };
let obj2 = { name: "Usman" };

function sayHi() {
  console.log("Hi " + this.name);
}

sayHi.call(obj2);
Enter fullscreen mode Exit fullscreen mode

βœ” Using Array methods on non-arrays

const nums = {
  0: 4,
  1: 8,
  length: 2
};

console.log(Array.prototype.join.call(nums, "-"));
Enter fullscreen mode Exit fullscreen mode

βœ” Fixing this in event handlers

button.addEventListener("click", obj.method.bind(obj));
Enter fullscreen mode Exit fullscreen mode

βœ” Currying with bind

function multiply(a, b) {
  return a * b;
}

const double = multiply.bind(null, 2);
console.log(double(5)); // 10
Enter fullscreen mode Exit fullscreen mode

🧨 7. Tricky & Important Behaviors


❗ Arrow functions IGNORE call/apply/bind

const obj = { a: 10 };

const x = () => console.log(this.a);
x.call(obj);  // ❌ still not obj
Enter fullscreen mode Exit fullscreen mode

Arrow functions use lexical this, so you cannot change it.


❗ bind creates a new function (original stays unchanged)

function a() {}
const b = a.bind({});
console.log(a === b); // false
Enter fullscreen mode Exit fullscreen mode

❗ Multiple binds β†’ first one wins

const x = greet.bind(obj1).bind(obj2);
x(); // uses obj1
Enter fullscreen mode Exit fullscreen mode

⚑ 8. Browser vs Node?

No difference in behavior.

call/apply/bind work the same in both.
Only the default this differs, not these methods.


🧩 9. Practice Problems


βœ… EASY (3 Problems)


Problem 1 β€” Output?

function say() {
  console.log(this.x);
}

const obj = { x: 10 };

say.call(obj);
Enter fullscreen mode Exit fullscreen mode

Solution

10
Enter fullscreen mode Exit fullscreen mode

Problem 2 β€” Output?

function sum(a, b) {
  console.log(a + b);
}

sum.apply(null, [5, 7]);
Enter fullscreen mode Exit fullscreen mode

Solution

12
Enter fullscreen mode Exit fullscreen mode

Problem 3 β€” Output?

function greet(name) {
  console.log("Hi " + name);
}

const g = greet.bind(null, "Usman");
g();
Enter fullscreen mode Exit fullscreen mode

Solution

Hi Usman
Enter fullscreen mode Exit fullscreen mode

⚑ MEDIUM (3 Problems)


Problem 1 β€” Output?

const user = {
  name: "Ali",
  say() {
    console.log(this.name);
  }
};

const fn = user.say;
fn.call(user);
Enter fullscreen mode Exit fullscreen mode

Solution

Ali
Enter fullscreen mode Exit fullscreen mode

Problem 2 β€” Output?

function add(a, b) {
  console.log(this.x + a + b);
}

const obj = { x: 5 };

add.call(obj, 10, 15);
Enter fullscreen mode Exit fullscreen mode

Solution

30
Enter fullscreen mode Exit fullscreen mode

Problem 3 β€” Output?

function intro(age, country) {
  console.log(this.name, age, country);
}

const p = { name: "Usman" };

intro.apply(p, [22, "PK"]);
Enter fullscreen mode Exit fullscreen mode

Solution

Usman 22 PK
Enter fullscreen mode Exit fullscreen mode

πŸ”₯ HARD (4 Problems)


Problem 1 β€” Output?

const a = { value: 50 };

function print() {
  console.log(this.value);
}

const b = print.bind(a);
b.call({ value: 100 });
Enter fullscreen mode Exit fullscreen mode

Solution

50
Enter fullscreen mode Exit fullscreen mode

Problem 2 β€” Output?

const obj = {
  x: 10,
  y: function() {
    console.log(this.x);
  }
};

const z = obj.y.bind({ x: 99 });
z();
Enter fullscreen mode Exit fullscreen mode

Solution

99
Enter fullscreen mode Exit fullscreen mode

Problem 3 β€” Output?

function show() {
  console.log(this.a);
}

const o1 = { a: 1 };
const o2 = { a: 2 };

const f = show.bind(o1);
f.call(o2);
Enter fullscreen mode Exit fullscreen mode

Solution

1
Enter fullscreen mode Exit fullscreen mode

Problem 4 β€” Output?

function multiply(a, b, c) {
  console.log(a * b * c);
}

const f = multiply.bind(null, 2);
f.apply(null, [3, 4]);
Enter fullscreen mode Exit fullscreen mode

Solution

24
Enter fullscreen mode Exit fullscreen mode

Congratulations on mastering this, call(), apply(), and bind()! To further enhance your JavaScript journey, I’ve developed a free, structured repository featuring topic-by-topic training, ranging from beginner to advanced levels, organized into a 42-day mastery plan. Completing this resource will significantly ease your transition into frameworks and stacks like React, Node, and Next.js.
πŸš€javascript-complete-mastery

Top comments (0)