The Magic of this, call(), apply(), and bind() in JavaScript
Learn about this keyword and learn how to control function context like a pro.

Search for a command to run...
Learn about this keyword and learn how to control function context like a pro.

No comments yet. Be the first to comment.
These are the assignments or knowledge dumps I decide to write for the "Chai aur Code's web Dev Cohort 2026"
Demystifying JavaScript’s most notorious keyword by simply asking: "Who called the function?"
RAG helps LLMs answer questions using your own data, but it doesn't guarantee correct answers. Here's how the pipeline works and where it commonly breaks down.

Imagine asking an AI, "Write a blog," versus "Act as an SEO expert and write a 1,000-word blog on AI safety formatted in markdown." The difference in the resulting output is night and day. A prompt is

Spotify and Apple Music make it incredibly easy to showcase your live listening habits on your website. YouTube Music? Not so much. After doing some setup you can do an API call and fetch your account

Arthur C. Clarke's famous third law: "Any sufficiently advanced technology is indistinguishable from magic" perfectly captures how the pace of human innovation works. From carrying supercomputers in o

Why HTTP is amnesiac, the difference between transport and state, and how to choose the right auth strategy for your Node.js app.
If you ask any JavaScript developer what the most confusing part of the language is, there is a very high chance they will say the this keyword.
It behaves differently depending on where you use it, how you call it, and whether or not you are in strict mode. But once you understand the simple mental model behind it, the mystery disappears. And once you master the tools to manipulate it—call(), apply(), and bind()—you unlock a whole new level of flexibility in your code.
Here is your straightforward, jargon-free guide to understanding context in JavaScript.
this actually mean?Instead of diving into deep compiler internals and execution contexts, let’s use a simple golden rule:
this simply refers to "who is calling the function right now."
Imagine a function is a phone call. If you pick up the phone and ask, "Who is this?", the answer depends entirely on who dialed your number.
In JavaScript, this is a dynamic reference to the object that invoked (called) the function.
this Inside ObjectsWhen a function is stored inside an object, it is called a method. When you call that method, this points directly to the object that holds it.
const user = {
name: "Alice",
age: 25,
introduce: function() {
// "this" refers to the 'user' object because 'user' called the function
console.log(`Hi, I am \({this.name} and I am \){this.age} years old.`);
}
};
user.introduce();
// Output: Hi, I am Alice and I am 25 years old.
Who is calling the function? The user object. Therefore, this.name translates to user.name.
this Inside Normal (Standalone) FunctionsWhen you call a function that is not a property of an object—just a plain function call—this depends on strict mode:
In non-strict mode, this falls back to the global object (in browsers, window or globalThis).
In strict mode, this becomes undefined.
Examples:
function show() {
console.log(this);
}
show(); // non-strict: window (in browser)
// strict: undefined (if 'use strict' at top)
Why that matters: if you expect this to refer to some object but you call the function without that object as the caller, you get the global object or undefined instead—leading to bugs (e.g., accidentally creating globals, or TypeErrors when accessing properties on undefined).
Common gotcha: extracting a method out of its object:
const user = {
name: 'Ada',
greet() { console.log(this.name); }
};
const greet = user.greet;
greet(); // undefined (strict) or '' (global.name) — you lost the user binding
To preserve the intended this, use explicit binding (next section), call it as a method (user.greet()), or use an arrow function bound in the right scope.
this with Constructors and newWhen you call a function with new, JavaScript:
Creates a fresh object,
Sets this inside the function to that new object,
Returns the object (unless the function explicitly returns another object).
Example:
function Person(name) {
this.name = name;
}
const p = new Person('Lin');
console.log(p.name); // "Lin"
Important precedence rule (short): "new" binding takes priority over implicit/explicit binding. If you try to force a this with call/apply on a constructor, new will still create the instance and use it as this instead.
this in Arrow Functions (lexical this)Arrow functions do not have their own this. Instead they inherit this from the surrounding (lexical) scope — like closures for this.
const obj = {
value: 42,
regular() { console.log(this.value); }, // 42
arrow: () => console.log(this.value) // likely undefined or outer scope value
};
obj.regular(); // 42
obj.arrow(); // not 42 — arrow's `this` is set where the function was defined
Use arrow functions when you want to preserve the outer this (commonly used in callbacks), but do NOT use them as object methods or constructors.
These are the explicit tools to set this for a function.
fn.call(thisArg, ...args) — call fn immediately with thisArg and a list of args.
fn.apply(thisArg, argsArray) — call fn immediately with thisArg and arguments as an array.
fn.bind(thisArg, ...boundArgs) — return a NEW function permanently bound to thisArg (and optionally pre-filled args).
Examples and typical use cases:
Borrowing a method:
const obj = { name: 'Ada' };
function say(greeting) {
console.log(greeting + ', ' + this.name);
}
say.call(obj, 'Hello'); // "Hello, Ada"
say.apply(obj, ['Hi']); // "Hi, Ada"
Using apply with arrays (common pre-spread era):
const nums = [3, 1, 4];
Math.max.apply(null, nums); // 4
// Modern alternative: Math.max(...nums)
Partial application with bind:
function multiply(a, b) { return a * b; }
const double = multiply.bind(null, 2);
console.log(double(5)); // 10
Keeping method this when passing as callback:
class Button {
constructor() {
this.count = 0;
this.onClick = this.onClick.bind(this); // ensure `this` inside onClick is the instance
}
onClick() {
this.count++;
console.log(this.count);
}
}
const btn = new Button();
setTimeout(btn.onClick, 100); // Works because bound
Notes:
call vs apply: same effect; apply accepts arguments as an array.
bind returns a new function; use it when you need a stable this for future calls (event handlers, callbacks).
Historically, null/undefined passed to call/apply default to global object in non-strict mode; in strict mode they remain null/undefined.
Precedence summary (most to least):
new
call/apply/bind (explicit)
method-call (implicit)
global/default
Edge detail: using bind and then new — the bound thisArg is ignored when constructing; the new instance becomes this, but bound arguments remain prepended.
Method borrowing:
Array.prototype.slice.call(arguments) (older pattern) to convert arguments to array. Now prefer Array.from(arguments) or rest params.Event handlers in classes:
Bind handlers in constructor, or use class fields with arrow functions:
handleClick = () => { console.log(this); }
Partial application:
bind is a simple built-in way to pre-fill arguments.Function utilities:
call/apply let you reuse generic functions on different objects.Losing this when passing methods as callbacks — use bind, arrow functions, or wrap in another function.
Incorrect assumptions about this inside arrow functions — remember arrow functions get this lexically.
Accidentally relying on global this in non-strict mode — always use strict mode or prefer explicit bindings.
Overusing bind for performance-critical hot paths — binds create new functions each time; cache the bound function if reused.
Method call: obj.fn() → this is obj.
Function call: fn() → non-strict: global; strict: undefined.
Constructor: new Fn() → this is the new instance.
Arrow function: () => {} → this is inherited from outer scope.
Explicit: fn.call(obj, ...), fn.apply(obj, [...]), fn.bind(obj) → force this.
Conclusion
Understanding this becomes simple if you apply the golden rule: think about "who is calling the function right now" and remember the four primary binding ways (default, implicit, explicit, and new), plus the special lexical behavior of arrow functions. Once you can identify which binding is in effect, call, apply, and bind give you the tools to control or preserve that binding when you need to.