apply( ) polyfill
Prompt
Implement a polyfill for the JavaScript .apply() method. Add a myApply method to Function.prototype that works exactly like the native .apply(), without using .call(), .apply(), or .bind().
Playground
.apply() is almost identical to .call(). The only
difference is how arguments are passed: .call() takes
them individually, .apply() takes them as an array. If
you've solved the .call() polyfill, the approach is the
same.
Temporarily attach the function as a method on the context
object (using a Symbol for a unique key), call it with
the spread operator to unpack the arguments array, then
clean up.
Solution
Explanation
If you've already solved the call() polyfill, you're 90% done. .apply() does the exact same thing as .call(), with one small difference in how you pass arguments:
// call: arguments passed one by one
greet.call(person, 'Hello', '!');
// apply: arguments passed as an array
greet.apply(person, ['Hello', '!']);That's it. Same this binding, same immediate execution, same return value. The only change is the function signature: instead of (context, ...args) with rest parameters, .apply() takes (context, argsArray) where the second parameter is a single array.
The implementation
The technique is identical to .call(). We temporarily attach the function to the context object using a Symbol key, call it as a method (so this points to the context), then clean up.
Function.prototype.myApply = function (context, argsArray) {
context = context || globalThis;
argsArray = argsArray || [];
const fnKey = Symbol();
context[fnKey] = this;
const result = context[fnKey](...argsArray);
delete context[fnKey];
return result;
};The extra line argsArray = argsArray || [] handles the case where someone calls .myApply(context) without passing an arguments array at all. Without this, we'd try to spread undefined and get an error.
When would you use apply over call?
In modern JavaScript, it honestly doesn't matter much because you can spread an array into .call():
const args = [1, 2, 3];
fn.call(context, ...args); // works fine
fn.apply(context, args); // same resultBut .apply() was essential before the spread operator existed (pre-ES6). A classic example was finding the max of an array:
// Before ES6 - needed apply
Math.max.apply(null, [1, 5, 3]); // 5
// After ES6 - spread works
Math.max(...[1, 5, 3]); // 5You'll still see .apply() in older codebases and interview questions.
All three polyfills (.call(), .apply(), .bind()) use
the same underlying trick: temporarily attaching a
function to an object to control this. .call() and
.apply() execute immediately, while .bind() wraps this
trick inside a returned function for later execution.