-/**
- * Creates a bound function from the provided function using the
- * provided this value and arguments list.
- *
- * ☡ As with call and construct, the arguments must be passed as an
- * array.
- */
-export const bind = (() => {
- const callBind = Function.prototype.call.bind(
- Function.prototype.bind,
- );
- const bind = ($, boundThis, boundArgs) =>
- callBind($, boundThis, ...boundArgs);
- return bind;
+export const {
+ /**
+ * Creates a bound function from the provided function using the
+ * provided this value and arguments list.
+ *
+ * ☡ As with `call` and `construct`, the arguments must be passed as
+ * an array.
+ */
+ bind,
+
+ /**
+ * Returns a new function which calls the provided function with its
+ * first argument as the `this` value and the remaining arguments
+ * passed through.
+ *
+ * ※ This is effectively an alias for `Function::call.bind`.
+ */
+ makeCallable,
+} = (() => {
+ // ☡ Because these functions are used to initialize module constants,
+ // they can’t depend on imports from elsewhere.
+ const {
+ bind: functionBind,
+ call: functionCall,
+ } = Function.prototype;
+ const callBind = Reflect.apply(functionBind, functionCall, [
+ functionBind,
+ ]);
+ const {
+ create: objectCreate,
+ defineProperty: defineOwnProperty,
+ getPrototypeOf: getPrototype,
+ } = Object;
+ const { [ITERATOR]: arrayIterator } = Array.prototype;
+ const {
+ next: arrayIteratorNext,
+ } = getPrototype([][ITERATOR]());
+ const argumentIterablePrototype = {
+ [ITERATOR]() {
+ return {
+ next: callBind(
+ arrayIteratorNext,
+ call(arrayIterator, this.args, []),
+ ),
+ };
+ },
+ };
+ return {
+ bind: ($, boundThis, boundArgs) =>
+ callBind(
+ $,
+ boundThis,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: boundArgs } },
+ ),
+ ),
+ makeCallable: ($) =>
+ defineOwnProperty(
+ callBind(functionCall, $),
+ "length",
+ { value: $.length + 1 },
+ ),
+ };