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)