bind( ) polyfill
Prompt
Implement a polyfill for the JavaScript .bind() method. Add a myBind method to Function.prototype that works exactly like the native .bind(), without using .bind() itself.
Playground
When someone calls greet.myBind(person), the this
inside myBind refers to greet (the function being
bound). You'll need to save that reference because this
will mean something different inside the returned
function.
.bind() can pre-fill some arguments at bind time, and
the rest get passed at call time. You need to combine both
sets of arguments in the right order: bind-time arguments
first, then call-time arguments.
You can't use .bind() itself, but you can use
.apply() inside your implementation. .apply() lets you
call a function with a specific this and an array of
arguments.
Solution
Explanation
.bind() is different from .call() and .apply(). Those two execute the function immediately. .bind() doesn't execute anything. It takes a function and returns a brand new function with two things permanently locked in:
- What
thisshould be - Optionally, some arguments pre-filled
This is useful when you need to pass a function somewhere (like an event handler or a callback) but you want to make sure it always runs with the right this and the right arguments.
const greetAlice = greet.bind(person);
// greetAlice is a new function
// whenever you call greetAlice(), this = person
button.addEventListener('click', greetAlice);
// even when the browser calls greetAlice later,
// this will still be person, not the buttonWhy do we save this in a variable?
This is the part that trips people up. When someone writes greet.myBind(person), the this inside myBind is greet (the function we want to bind). We need to save it:
const fn = this; // fn = greetWhy? Because we're about to return a new function. When that new function gets called later (maybe seconds, maybe minutes later), this inside it won't be greet anymore. It'll be whatever object called it. By saving greet in fn now, we can use it later inside the returned function. This is a closure in action.
How partial application works
This is the other concept worth understanding. .bind() lets you "pre-fill" some arguments:
function add(a, b) {
return a + b;
}
const addFive = add.bind(null, 5);
addFive(3); // 8
addFive(10); // 15addFive always passes 5 as the first argument. Whatever you pass when you call addFive becomes the second argument.
In our polyfill, we handle this with two sets of arguments:
bindArgs= arguments passed when.myBind()is called (e.g.,[5])callArgs= arguments passed when the returned function is called (e.g.,[3])
We combine them: [...bindArgs, ...callArgs] gives us [5, 3]. Bind-time arguments always come first.
Walking through a full example
const person = { name: 'Alice' };
function introduce(greeting, punctuation) {
return `${greeting}, I am ${this.name}${punctuation}`;
}
const introduceAlice = introduce.myBind(person, 'Hi');
introduceAlice('!');myBindis called onintroduce.fn = introduce,context = person,bindArgs = ['Hi']- A new function is returned and stored in
introduceAlice - When we call
introduceAlice('!'),callArgs = ['!'] - Combined args:
['Hi', '!'] - Internally it runs
introduce.apply(person, ['Hi', '!']) introduceexecutes withthis = person,greeting = 'Hi',punctuation = '!'- Returns:
"Hi, I am Alice!"
We wrap the polyfill in if (!Function.prototype.myBind)
to avoid overwriting it if it already exists. This is
standard practice for polyfills. You never blindly
overwrite existing functionality.