The syntax function[i][]{}
implies an object with property values that are functions, function[]
, indexed by the name, [i]
.
Thus
{"f:1":function[]{}, "f:2":function[]{}, "f:A":function[]{}, ... } ["f:"+i]
.
{"f:1":function f1[]{}, "f:2":function f2[]{}, "f:A":function fA[]{}} ["f:"+i]
will preserve function name identification. See notes below regarding :
.
So,
javascript: alert[
new function[a]{
this.f={"instance:1":function[]{}, "instance:A":function[]{}} ["instance:"+a]
}["A"] . toSource[]
];
displays [{f:[function [] {}]}]
in FireFox.
[This is almost the same idea as this solution, only it
uses a generic object and no longer directly populates the window object with the functions.]
This method explicitly populates the environment with instance:x
.
javascript: alert[
new function[a]{
this.f=eval["instance:"+a+"="+function[]{}]
}["A"] . toSource[]
];
alert[eval["instance:A"]];
displays
[{f:[function [] {}]}]
and
function [] {
}
Though the property function f
references an anonymous function
and not instance:x
, this method avoids several problems with this solution.
javascript: alert[
new function[a]{
eval["this.f=function instance"+a+"[]{}"]
}["A"] . toSource[]
];
alert[instanceA]; /* is undefined outside the object context */
displays only
[{f:[function instanceA[] {}]}]
- The embedded
:
makes the javascriptfunction instance:a[]{}
invalid. - Instead of a reference, the function's actual text definition is parsed and interpreted by
eval
.
The following is not necessarily problematic,
- The
instanceA
function is not directly available for use asinstanceA[]
and so is much more consistent with the original problem context.
Given these considerations,
this.f = {"instance:1": function instance1[]{},
"instance:2": function instance2[]{},
"instance:A": function instanceA[]{},
"instance:Z": function instanceZ[]{}
} [ "instance:" + a ]
maintains the global computing environment with the semantics and syntax of the OP example as much as possible.
Say you're writing some higher order functions that return other functions. In my case it was a utility that creates a typed hook to consume some context.
I wanted to let the consumer of this utility to have a reasonable
name
property on the hook returned, not some generic library code name like "useContext"
.
The first attempt did not work.
const someFunc = [] => { ... }
someFunc.name = someConfig.name
Enter fullscreen mode Exit fullscreen mode
You get a nice error at least.
So then I think to myself 🤔 Do I know anything about dynamic naming in general in JavaScript?
💡
Objects can have dynamic keys! With square brackets, we can stringify runtime values.
{ [someVar]: "woohoo" }
Enter fullscreen mode Exit fullscreen mode
So, to solve my configurable function name problem, I used computed keys to create an object and computed keys again to destructure the function value.
🤯 Right?
const custom = "Jerome"
const { [custom]: someFunc } = { [custom]: [] => void 0 }
someFunc.name === "Jerome" // true
Enter fullscreen mode Exit fullscreen mode
^ You can try that example in your browser console.
Pretty neat stuff! Here was my final solution, inspired by this cheatsheet.
import * as React from 'react';
export function assertContext[
context: T | undefined,
config: {
hookName: string;
providerName: string;
},
]: asserts context is T {
if [typeof context === 'undefined'] {
throw new Error[`\`${config.hookName}\` must be used within \`\``];
}
}
export function createUsableContext[config: {
hookName: string;
providerName: string;
}]: [[] => T, React.Context] {
const Context = React.createContext[undefined];
// assign the function name dynamically by instantaneously assigning and destructuring an object field
// const useContext = ... would result in the fn name being `useContext`. Not helpful.
const { [config.hookName]: useContext } = {
[config.hookName]: []: T => {
const context = React.useContext[Context];
assertContext[context, config];
return context;
},
};
return [useContext, Context];
}
Enter fullscreen mode Exit fullscreen mode