As we all know...
var/let/const foo = function() {}
...
foo's function hasn't got its own name...
A partire dal ES2015 +, la funzione di foo ha in effetti un nome: foo
. ES2015 ha aggiunto molti punti in cui le funzioni ottengono i nomi anche se definiti con espressioni di funzione "anonime". Questo include semplici incarichi come quello, assegnazioni a proprietà (compresi i nomi di proprietà calcolati) e altri simili. Cerca le specifiche per "SetFunctionName" per i dettagli.
Ma, come squint sottolinea nel a comment, in ES2015 +, il nome di una funzione può essere impostata tramite Object.defineProperty
:
Object.defineProperty(foo, "name", {value: "aNameForFoo"});
Non si può semplicemente assegnare al foo.name
perché name
è definito come non-scrivibile. Ma è configurabile (è possibile scambiare la proprietà con una nuova), quindi funziona sopra. (I dettagli su come è definito in the spec.)
Nota che Function#name
è nuova come di ES2015, e come era una caratteristica molto minore, è stato una delle priorità più basse per gli sviluppatori del motore JavaScript. Credo che Chrome 51 sia stato il primo browser con un motore JavaScript che implementa correttamente le specifiche. Questo cambierà rapidamente in questa fase.
Ma, come Assimilater punti fuori, se si desidera solo la funzione creata con l'espressione di avere un nome e tu non ne hai bisogno definito in fase di esecuzione, basta usare un chiamato funzione di espressione (NPC):
var foo = function bar() {
// Note ------^^^^
}
//console.log(bar); // Would throw a ReferenceError, `bar` is not defined in this scope
console.log(foo.name); // "bar"
Gli NFE sono in circolazione da sempre, molto prima dell'ES2015. In alcuni motori erano problematici (molto presto Safari, IE8 e precedenti), ma i motori moderni (IE9 +) li gestivano correttamente.
Ecco un esempio di:
- Il nome "dedotto"
- Il nome aggiornato
- Un nome assegnato da un NPC
// "Inferred" name is foo
var foo = function() {
throw new Error();
};
try {
foo();
} catch (e) {
console.log(e.stack);
}
// Change it to "updatedName"
Object.defineProperty(foo, "name", {
value: "updatedName"
});
try {
foo();
} catch (e) {
console.log(e.stack);
}
// Example of NFE
var foo2 = function bar() {
// Note --------^^^^
console.log("bar is defined within the function: " + bar.name);
throw new Error();
};
//console.log(bar); // Would throw an error, `bar is not
// defined here
console.log(foo2.name); // "bar"
try {
foo2();
} catch (e) {
console.log(e.stack);
}
Su un browser che implementa ES2015 di Function#name
correttamente (molto pochi lo fanno partire da questa scrittura, Chrome 51 essendo uno dei primi), e che implementa Error#stack
, che le uscite:
Error
at foo (http://stacksnippets.net/js:15:9)
at http://stacksnippets.net/js:18:3
Error
at updatedName (http://stacksnippets.net/js:15:9)
at http://stacksnippets.net/js:28:3
bar
bar is defined within the function: bar
Error
at bar (http://stacksnippets.net/js:37:9)
at http://stacksnippets.net/js:43:3
Una nota su "inferito "nomi per funzioni definite da espressioni anonime. Considerare:
let Nifty = {
stuff: {
here: {
foo: function() { throw new Error(); }
}
}
};
let f = Nifty.stuff.here.foo;
console.log(f.name); // "foo"
Si potrebbe ragionevolmente pensare che la funzione finirebbe per essere Nifty.stuff.here.foo
, o foo
. È il secondo. (Questo nome di inferenza "ES2015" è venuto fuori dagli sforzi di Google e Mozilla per fornire nomi utili per le funzioni nei loro strumenti di sviluppo.In uno stadio, uno o l'altro — Ho dimenticato quale — utilizzava il nome completo, ma sembra non sono stati popolari)
Forse degno di nota:. è possibile scegliere un nome runtime quando sua creazione, come di ES2015, tramite un nome di proprietà computerizzata:
var name = "function" + Math.floor(Math.random() * 10000);
var obj = {[name]: function() { throw new Error(); }};
var foo = obj[name];
try {
foo();
} catch (e) {
console.log(e.stack);
}
uscita su un browser che supporti questa roba:
Error
at function3608 (http://stacksnippets.net/js:14:39)
at http://stacksnippets.net/js:17:3
Ma ora che so che si può fare la Object.defineProperty
trucco, beh, che sembra meno intelligente. :-)
Hai provato 'foo.name = 'foo';'? – jonhopkins
'Object.defineProperty (foo," name ", {value:" foo "})' –
@jonhopkins L'hai * provato *? : -3 – deceze