Implement Function.prototype.myCall — a from-scratch version of Function.prototype.call. Given any function, fn.myCall(thisArg, ...args) invokes the function immediately with thisArg as its this and args spread out as the arguments.
This is the runtime hook the language uses for method borrowing — Array.prototype.slice.call(arguments) is the classic example. You're rebuilding that hook by hand.
// Installed on Function.prototype.
fn.myCall(thisArg: any, ...args: any[]): any
// ^ invokes fn immediately with `this === thisArg` and arguments === args
function greet(greeting, name) {
return `${greeting}, ${name}! I am ${this.role}.`;
}
greet.myCall({ role: 'admin' }, 'Hi', 'Ana');
// → "Hi, Ana! I am admin."
// Method borrowing — the canonical use case.
const arrayLike = { 0: 'a', 1: 'b', length: 2 };
Array.prototype.slice.myCall(arrayLike);
// → ['a', 'b']
// thisArg is forwarded verbatim — null/undefined just pass through.
function readType() { return typeof this; }
readType.myCall(null);
// → 'object' in sloppy mode (boxed to global), 'undefined' in strict
bind, call runs the function right now and returns its result. Nothing is deferred.thisArg wins for this one call — set this for the invocation; don't permanently bind it.fn.myCall(t, 1, 2, 3) is fn(1, 2, 3) with this === t. No array packing.null / undefined are passed through as-is. Don't special-case them; the underlying invocation does the right thing per its own mode.Function.prototype.call, .apply, and .bind are off-limits. The whole point is to reproduce the this-binding from primitives.