Explicit Binding: call, apply and bind
In short: instead of hoping a function gets called the right way,
three methods let you set this directly. fn.call(obj, a, b) runs
fn immediately with this = obj, arguments listed one by one.
fn.apply(obj, [a, b]) does the exact same thing, but arguments are
packed into a single array. fn.bind(obj) doesn't run anything — it
returns a new function permanently locked to this = obj, which you
can call later, as many times as you like. A bound function's this stays
fixed even if you later try call or apply on it.
![announce(greeting) with three arrows: .call(song, "Hi") runs NOW, this = song, args listed one by one; .apply(song, ["Hi"]) runs NOW, this = song, args packed in an array; .bind(song) doesn't run yet — hands back a new, permanently bound function — plus function borrowing: Array.prototype.join.call(arrayLike, "-")](/api/assets/javascript/assets/a190b918c9055d01.png)
Run the same function with three different this values
call and apply both run the function right away — only their argument
style differs:
Both lines print "Now playing, Blue Hour" — this is song in each
call. The only difference: call takes "Now playing" as a normal
argument after song; apply takes the same argument wrapped in an
array, ["Now playing"]. Everything else about them is identical.
Lock a function's this for later
bind doesn't call the function — it returns a new one, with this
already decided, ready to be called whenever you want:
announce.bind(song) produces bound, a function forever tied to
this = song. Calling bound(...) later — once, or many times — always
uses song, with no need to repeat .call(song, ...) every time. This is
exactly how you'd prepare a callback (for a timer or an event listener)
that needs a specific this once it eventually runs.
Borrow a method that wasn't written for you
call also lets an object use a method that belongs to a completely
different type — as long as the object's shape is close enough:
arrayLike isn't a real array — it's a plain object that merely has
numbered properties and a length. Array.prototype.join doesn't care:
called with this = arrayLike via .call, it reads arrayLike[0],
arrayLike[1] and arrayLike.length exactly as it would on a real array,
printing "Blue Hour / Red Dawn".
The trap: assuming bind can be undone
Once a function is bound, that binding is permanent — later trying call
or apply on it to supply a different this is silently ignored:
This still prints "Hi, Blue Hour", not "Hi, Red Dawn" — bound.call
tries to set this = other, but bound's this was already locked by
bind and cannot be changed again.
Quick practice
What's the one real difference between fn.call(obj, a, b) and fn.apply(obj, [a, b])?
What does fn.bind(obj) do?
After const bound = announce.bind(song);, what does bound.call(other, "Hi") do?
What does Array.prototype.join.call(arrayLike, " / ") demonstrate?
Which of call, apply and bind actually runs the function right away?
🎯 Your turn
Given
function announce(greeting) { console.log(greeting + ", " + this.title); } const song = { title: "Blue Hour" };,
explain what announce.call(song, "Hi"), announce.apply(song, ["Hi"]),
and const bound = announce.bind(song); bound("Hi"); each do, and the one
real difference between call and apply.
Write your explanation and submit it — there's no code to run here, just your reasoning.
