Explicit Binding
Force `this` with call, apply, and bind
LinkedIn Hook
Imagine you have a friend's phone. Normally every call you make shows your friend's caller ID. But what if you could FORCE any caller ID you wanted on every call?
That's exactly what
call,apply, andbinddo in JavaScript.They let you rip
thisout of the hands of implicit binding and pin it to whatever object you choose — including borrowing methods from one object and running them on another.One returns a new function. Two fire the function immediately. One of them takes an array. Mixing them up is an instant red flag in an interview.
In this lesson I break down all three, with a real-world method-borrowing example, and the polyfill for
bindthat senior interviewers love to ask.Read the full lesson -> [link]
#JavaScript #InterviewPrep #CallApplyBind #ExplicitBinding #Frontend #CodingInterview #Polyfill
What You'll Learn
- How
call,apply, andbinddiffer in invocation and argument style - How to borrow methods from one object and run them on another
- How to write a polyfill for
Function.prototype.bindfrom scratch
Forcing this — The Explicit Rule
Imagine you have a friend's phone. Normally when you call someone from it, the caller ID shows your friend's number. But what if you could force any caller ID you want? That's explicit binding — you manually tell JavaScript which object this should be.
call() — Invoke immediately, pass arguments one by one
function introduce(greeting, punctuation) {
console.log(greeting + ", I'm " + this.name + punctuation);
}
const person = { name: "Rakibul" };
introduce.call(person, "Hello", "!");
// "Hello, I'm Rakibul!"
apply() — Invoke immediately, pass arguments as an array
function introduce(greeting, punctuation) {
console.log(greeting + ", I'm " + this.name + punctuation);
}
const person = { name: "Rakibul" };
introduce.apply(person, ["Hey", "!!"]);
// "Hey, I'm Rakibul!!"
bind() — Returns a NEW function with this permanently set
function introduce(greeting) {
console.log(greeting + ", I'm " + this.name);
}
const person = { name: "Rakibul" };
const boundIntroduce = introduce.bind(person);
boundIntroduce("Hi"); // "Hi, I'm Rakibul"
boundIntroduce("Hello"); // "Hello, I'm Rakibul"
// Even calling with a different context won't change it
const other = { name: "Karim" };
boundIntroduce.call(other, "Hey"); // "Hey, I'm Rakibul" — bind wins!
call vs apply vs bind — Quick Comparison
| Method | Invokes Immediately? | Arguments Format | Returns |
|---|---|---|---|
call | Yes | call(thisArg, arg1, arg2, ...) | Function result |
apply | Yes | apply(thisArg, [arg1, arg2, ...]) | Function result |
bind | No | bind(thisArg, arg1, arg2, ...) | New function |
Memory trick: apply takes an array. bind gives you back a function.
Real-World Use Case — Borrowing Methods
const calculator = {
value: 0,
add: function(num) {
this.value += num;
return this;
}
};
const myCounter = { value: 100 };
// Borrow the 'add' method from calculator but use it on myCounter
calculator.add.call(myCounter, 50);
console.log(myCounter.value); // 150
Polyfill for bind — A Classic Interview Question
Understanding how bind works under the hood is a common senior-level question.
Function.prototype.myBind = function(context, ...boundArgs) {
const fn = this; // the original function
return function(...callArgs) {
return fn.apply(context, [...boundArgs, ...callArgs]);
};
};
// Usage
function greet(greeting, punctuation) {
return greeting + ", " + this.name + punctuation;
}
const person = { name: "Rakibul" };
const boundGreet = greet.myBind(person, "Hello");
console.log(boundGreet("!")); // "Hello, Rakibul!"
How the polyfill works:
thisinsidemyBindis the original function (becausegreet.myBind(...)uses implicit binding)- We save it as
fn - We return a new function that, when called, uses
applyto call the original function with the saved context - We merge pre-set arguments (
boundArgs) with new arguments (callArgs)
Common Mistakes
- Forgetting that
binddoes NOT invoke the function — writingfn.bind(obj)()instead offn.bind(obj), or expecting output when nothing ran. - Passing arguments to
applyindividually (apply(obj, a, b)) instead of as an array (apply(obj, [a, b])) —applysilently ignores extras. - Trying to "re-bind" a bound function — once
bindpinsthis, latercall/apply/bindcalls on the bound function cannot change it.
Interview Questions
Q: What does call() do?
call()invokes the function immediately with a specifiedthisvalue, passing any remaining arguments one by one after thethisArg.
Q: What does apply() do? How is it different from call()?
apply()also invokes the function immediately with a specifiedthis, but it takes the arguments as a single array.callpasses args individually;applytakes an array.
Q: What does bind() return?
bind()returns a brand new function wherethisis permanently locked to the provided object. It does not invoke the original function — you must call the returned function yourself.
Q: Can you re-bind a function already bound with bind()?
No. Once a function is bound with
bind, callingbindagain or evencall/applyon the bound function will NOT changethis. The firstbindwins permanently.
Q: What's the difference between call, apply, and bind?
callandapplyboth invoke the function immediately with a specifiedthis. The difference is thatcalltakes arguments individually whileapplytakes them as an array.binddoes NOT invoke the function — it returns a new function withthispermanently bound.
Q: Write a polyfill for Function.prototype.bind.
See the
myBindimplementation above. The key insight is: save the original function reference, return a closure that callsfn.apply(context, mergedArgs)when invoked, merging pre-setboundArgswith freshcallArgs.
Quick Reference — Cheat Sheet
EXPLICIT BINDING — QUICK MAP
call(thisArg, a, b, c) -> runs NOW, args individual
apply(thisArg, [a, b, c]) -> runs NOW, args as array
bind(thisArg, a, b) -> returns NEW fn, never runs now
Memory trick:
Apply -> Array
Bind -> gives you Back a function
Method borrowing:
other.fn.call(myObj, ...args)
bind is sticky:
boundFn.call(anotherObj) // ignored; bind wins
Polyfill skeleton:
Function.prototype.myBind = function(ctx, ...pre) {
const fn = this;
return function(...later) {
return fn.apply(ctx, [...pre, ...later]);
};
};
Previous: Implicit Binding -> The Dot Decides Next: new Binding -> The 4-Step Factory
This is Lesson 4.2 of the JavaScript Interview Prep Course — 14 chapters, 87 lessons.