Esiste un modo non eval per creare una funzione con un nome determinato dal tempo di esecuzione?

Esiste un modo per creare una funzione con un nome reale determinata in fase di esecuzione senza utilizzare eval e utilizzando solo JavaScript puro? (Quindi, nessun elemento di script generato, in quanto sono specifici per l’ambiente del browser [e in molti modi verrebbe comunque eval sotto mentite spoglie]; non utilizzare le caratteristiche non standard di un particolare motore JavaScript, ecc.)

Nota che in particolare non sto chiedendo di funzioni anonime a cui fanno riferimento variabili o proprietà con nomi, ad esempio:

 // NOT this var name = /* ...come up with the name... */; var obj = {}; obj[name] = function() { /* ... */ }; 

Lì, mentre la proprietà dell’object ha un nome, la funzione no. Le funzioni anonime vanno bene per molte cose, ma non per quello che sto cercando qui. Voglio che la funzione abbia un nome (ad es. Per presentarsi negli stack di chiamate nei debugger, ecc.).

La risposta per ECMAScript 2015 (aka “ES6”) :

A partire da ES2015, la funzione creata da un’espressione di funzione anonima assegnata a una proprietà dell’object prende il nome di tale proprietà dell’object. Mentre scrivo questo l’11 maggio 2015, nessun motore JavaScript in circolazione diverso da Microsoft “Project Spartan” per Windows 10 Preview supporta questo (sì, avete letto bene, M $ è arrivato prima di Mozilla o Google) , ma è in le specifiche e le implementazioni raggiungeranno. Aggiornamento : a partire da ottobre 2016, le versioni recenti di Chrome implementano il Function#name e le varie regole per l’assegnazione dei nomi; Firefox non funziona, ma ci arriveranno.

Ad esempio, in ES2015 viene creata una funzione denominata “foo ###” dove ### è composta da 1-3 cifre:

 const dynamicName = "foo" + Math.floor(Math.random() * 1000); const obj = { [dynamicName]() { throw new Error(); } }; const f = obj[dynamicName]; // See its `name` property (Edge and Chrome for now, eventually Firefox will get it) console.log("Function's `name` property: " + f.name + " (see compatibility note)"); // We can see that it truly has a name (even in Firefox which doesn't have the `name` property yet) via an exception: try { f(); } catch (e) { console.log(e.stack); } 

Ecco una funzione di utilità che ho trovato qualche tempo fa. Utilizza la tecnica di costruzione Function come descritto nell’ottima risposta di @ TJCrowder, ma migliora i suoi svantaggi e consente un controllo a grana fine sull’ambito della nuova funzione.

 function NamedFunction(name, args, body, scope, values) { if (typeof args == "string") values = scope, scope = body, body = args, args = []; if (!Array.isArray(scope) || !Array.isArray(values)) { if (typeof scope == "object") { var keys = Object.keys(scope); values = keys.map(function(p) { return scope[p]; }); scope = keys; } else { values = []; scope = []; } } return Function(scope, "function "+name+"("+args.join(", ")+") {\n"+body+"\n}\nreturn "+name+";").apply(null, values); }; 

Ti consente di essere in ordine e di evitare l’accesso completo al tuo ambito tramite eval , ad esempio nello scenario sopra riportato:

 var f = NamedFunction("fancyname", ["hi"], "display(hi);", {display:display}); f.toString(); // "function fancyname(hi) { // display(hi); // }" f("Hi");