The spec defines bind through a bound function exotic object. It stores [[BoundTargetFunction]], [[BoundThis]] and [[BoundArguments]], and its internal methods do two things:
[[Call]]: call the target with[[BoundThis]]and[[BoundArguments]]followed by the call's own arguments. Thethisof the call is ignored.[[Construct]]: construct the target with the bound arguments prepended, ignoring[[BoundThis]]. Ifnew.targetis the bound function itself, it is replaced by the target.
A userland version needs to reproduce those two paths. A normal function can tell them apart through new.target, which is undefined for a plain call. Reflect.apply and Reflect.construct are the clean primitives: the first calls with an explicit this, the second constructs with an explicit new.target, so a constructed object gets the right prototype.
Use the rest parameter and spread for argument merging; the old Array.prototype.slice.call(arguments) is no longer needed. Validate the target, as the spec does, with a TypeError.
What it can't replicate:
- The result is a normal function. It has an own
prototype(non-configurable, so you can't delete it), sonew bound() instanceof boundisfalse, where for a native bound functioninstanceofis delegated to the target. nameandlengthare those of the inner function unless you define them (bound <name>, target length minus bound arguments); they can be copied withObject.defineProperties.- Its
[[Prototype]]isFunction.prototype, not the target's, andtoStringshows your source, notfunction () { [native code] }. - It isn't a real exotic object, so engines can't treat it specially and tools can't see the target.
State these limits out loud in an interview; they show you know it is an approximation.