From: Lady Date: Sat, 22 Jul 2023 07:42:24 +0000 (-0700) Subject: Ensure each function in function.js has proper name X-Git-Url: https://git.ladys.computer/Pisces/commitdiff_plain/d807b9e7794776e0fad49b968346e94322d43a73 Ensure each function in function.js has proper name Also provides a wrapper for `constructor` for parity even though this isn’t strictly required, and simplifies the implementation of `isConstructor` to make use of `completesNormally`. --- diff --git a/function.js b/function.js index ca7cad5..d1d337a 100644 --- a/function.js +++ b/function.js @@ -39,7 +39,7 @@ export const { ]); const { create: objectCreate, - defineProperty: defineOwnProperty, + defineProperties: defineOwnProperties, getPrototypeOf: getPrototype, } = Object; const { [ITERATOR]: arrayIterator } = Array.prototype; @@ -66,12 +66,11 @@ export const { { args: { value: boundArgs } }, ), ), - makeCallable: ($) => - defineOwnProperty( - callBind(functionCall, $), - "length", - { value: $.length + 1 }, - ), + makeCallable: ($, name = undefined) => + defineOwnProperties(callBind(functionCall, $), { + length: { value: $.length + 1 }, + name: { value: name ?? $.name ?? "" }, + }), }; })(); @@ -80,20 +79,40 @@ export const { * Calls the provided function with the provided this value and * arguments list. * - * ☡ This is an alias for `Reflect.apply`—the arguments must be - * passed as an arraylike. + * ☡ This is effectively an alias for `Reflect.apply`—the arguments + * must be passed as an arraylike. */ - apply: call, + call, /** * Constructs the provided function with the provided arguments list * and new target. * - * ☡ This is an alias for `Reflect.construct`—the arguments must be - * passed as an arraylike. + * ☡ This is effectively an alias for `Reflect.construct`—the + * arguments must be passed as an arraylike. */ construct, -} = Reflect; + + /** Returns whether the provided value is a constructor. */ + isConstructor, +} = (() => { + const { apply, construct } = Reflect; + return { + call: (target, thisArgument, argumentsList) => + apply(target, thisArgument, argumentsList), + construct: (target, argumentsList, ...args) => + args.length > 0 + ? construct(target, argumentsList, args[0]) + : construct(target, argumentsList), + isConstructor: ($) => + completesNormally(() => + // Try constructing a new object with the provided value as its + // `new.target`. This will throw if the provided value is not a + // constructor. + construct(function () {}, [], $) + ), + }; +})(); /** * Returns whether calling the provided function with no `this` value @@ -136,29 +155,11 @@ export const identity = function ($) { /** Returns whether the provided value is callable. */ export const isCallable = ($) => typeof $ === "function"; -/** Returns whether the provided value is a constructor. */ -export const isConstructor = ($) => { - // The provided value is an object. - try { - // Try constructing a new object with the provided value as its - // `new.target`. This will throw if the provided value is not a - // constructor. - construct( - function () {}, - [], - $, - ); - return true; - } catch { - // The provided value was not a constructor. - return false; - } -}; - /** * Returns whether the provided object inherits from the prototype of * the provided function. */ export const ordinaryHasInstance = makeCallable( Function.prototype[Symbol.hasInstance], + "ordinaryHasInstance", ); diff --git a/function.test.js b/function.test.js index a9a5f3f..e928662 100644 --- a/function.test.js +++ b/function.test.js @@ -69,6 +69,12 @@ describe("bind", () => { ["etaoin", undefined, "shrdlu", undefined, "cmfwyp"], ); }); + + describe(".name", () => { + it("[[Get]] returns the correct name", () => { + assertStrictEquals(bind.name, "bind"); + }); + }); }); describe("call", () => { @@ -115,6 +121,12 @@ describe("call", () => { ["etaoin", undefined, "shrdlu", undefined, "cmfwyp"], ); }); + + describe(".name", () => { + it("[[Get]] returns the correct name", () => { + assertStrictEquals(call.name, "call"); + }); + }); }); describe("completesNormally", () => { @@ -142,6 +154,12 @@ describe("completesNormally", () => { completesNormally(); }); }); + + describe(".name", () => { + it("[[Get]] returns the correct name", () => { + assertStrictEquals(completesNormally.name, "completesNormally"); + }); + }); }); describe("construct", () => { @@ -200,6 +218,12 @@ describe("construct", () => { ["etaoin", undefined, "shrdlu", undefined, "cmfwyp"], ); }); + + describe(".name", () => { + it("[[Get]] returns the correct name", () => { + assertStrictEquals(construct.name, "construct"); + }); + }); }); describe("identity", () => { @@ -217,6 +241,12 @@ describe("identity", () => { const value = {}; assertStrictEquals(new class extends identity {}(value), value); }); + + describe(".name", () => { + it("[[Get]] returns the correct name", () => { + assertStrictEquals(identity.name, "identity"); + }); + }); }); describe("isCallable", () => { @@ -273,6 +303,12 @@ describe("isCallable", () => { it("[[Call]] returns false for objects", () => { assertStrictEquals(isCallable({}), false); }); + + describe(".name", () => { + it("[[Get]] returns the correct name", () => { + assertStrictEquals(isCallable.name, "isCallable"); + }); + }); }); describe("isConstructor", () => { @@ -329,6 +365,12 @@ describe("isConstructor", () => { it("[[Call]] returns false for objects", () => { assertStrictEquals(isConstructor({}), false); }); + + describe(".name", () => { + it("[[Get]] returns the correct name", () => { + assertStrictEquals(isConstructor.name, "isConstructor"); + }); + }); }); describe("makeCallable", () => { @@ -353,6 +395,12 @@ describe("makeCallable", () => { ["etaoin", "shrdlu", "cmfwyp"], ); }); + + describe(".name", () => { + it("[[Get]] returns the correct name", () => { + assertStrictEquals(makeCallable.name, "makeCallable"); + }); + }); }); describe("ordinaryHasInstance", () => { @@ -370,4 +418,13 @@ describe("ordinaryHasInstance", () => { true, ); }); + + describe(".name", () => { + it("[[Get]] returns the correct name", () => { + assertStrictEquals( + ordinaryHasInstance.name, + "ordinaryHasInstance", + ); + }); + }); });