Pourquoi utiliser des expressions de fonction nommées?

Nous avons deux façons différentes d’exprimer une fonction en JavaScript:

Expression de fonction nommée (NFE) :

var boo = function boo () { alert(1); }; 

Expression de fonction anonyme :

 var boo = function () { alert(1); }; 

Et les deux peuvent être appelés avec boo(); . Je ne peux vraiment pas voir pourquoi / quand je devrais utiliser des fonctions anonymes et quand je devrais utiliser des expressions de fonctions nommées. Quelle différence y a-t-il entre eux?

Dans le cas de l’expression de la fonction anonyme , la fonction est anonyme – littéralement, elle n’a pas de nom. La variable à laquelle vous l’affectez a un nom, mais la fonction ne l’a pas. (Mise à jour: c’était vrai par ES5. A partir de ES2015 [alias ES6], souvent une fonction créée avec une expression anonyme prend un vrai nom, continue à lire …)

Les noms sont utiles. Les noms peuvent être vus dans des traces de stack, des stacks d’appels, des listes de points d’arrêt, etc. Les noms sont une bonne chose ™.

Vous devez vous méfier des expressions de fonctions nommées dans les anciennes versions d’IE (IE8 et versions ultérieures), car IE crée par erreur deux objects fonction complètement séparés à deux moments complètement différents (plus d’informations dans l’article Double blog). Si vous avez besoin de prendre en charge IE8, il est préférable d’utiliser des expressions anonymes ou des déclarations de fonctions, mais évitez les expressions de fonctions nommées.

Cependant, à partir de ES2015, de nombreuses expressions de fonction “anonymes” créent des fonctions avec des noms, ce qui était précédé par l’utilisation de plusieurs moteurs JavaScript modernes qui permettaient de déduire les noms du contexte. Dans ES2015, votre expression de fonction anonyme génère une fonction portant le nom boo . Ceci est répandu dans toute la spécification plutôt que d’être défini à un endroit avec un tas de règles: Rechercher les occurrences de “SetFunctionName”, actuellement trouvé dans:

  • §12.2.6.9 (sémantique de l’initialiseur de propriété)
  • §12.14.4 (sémantique de l’opérateur d’atsortingbution)
  • §12.14.5.2 et §12.14.5.4 (sémantique d’affectation de déstructuration)
  • §13.3.1.4 (sémantique de la déclaration let et const )
  • … et un tas d’autres endroits.

La version courte est fondamentalement à chaque fois qu’une expression de fonction anonyme apparaît à droite de quelque chose comme une affectation ou une initialisation, comme:

 var boo = function() { /*...*/ }; 

(ou peut-être let ou const plutôt que var ) , ou

 var obj = { boo: function() { /*...*/ } }; 

ou

 doSomething({ boo: function() { /*...*/ } }); 

(ces deux derniers sont vraiment la même chose) , la fonction résultante aura un nom ( boo , dans les exemples).

Il existe une exception importante et intentionnelle: Affectation à une propriété sur un object existant:

 obj.boo = function() { /*...*/ }; // < == Does not get a name 

Cela était dû aux problèmes de fuite d’informations soulevés lors de l’ajout de la nouvelle fonctionnalité; détails dans ma réponse à une autre question ici .

Les fonctions de dénomination sont utiles si elles ont besoin de se référencer (par exemple pour les appels récursifs). En effet, si vous transmettez une expression de fonction littérale en tant qu’argument directement à une autre fonction, cette expression de fonction ne peut pas se référer directement au mode ssortingct ES5, sauf si elle est nommée.

Par exemple, considérons ce code:

 setTimeout(function sayMoo() { alert('MOO'); setTimeout(sayMoo, 1000); }, 1000); 

Il serait impossible d’écrire ce code assez clairement si l’expression de la fonction passée à setTimeout était anonyme; nous devions l’affecter à une variable avant l’appel setTimeout . Cette façon, avec une expression de fonction nommée, est légèrement plus courte et plus nette.

Il était historiquement possible d’écrire du code comme celui-ci même en utilisant une expression de fonction anonyme, en exploitant arguments.callee

 setTimeout(function () { alert('MOO'); setTimeout(arguments.callee, 1000); }, 1000); 

… mais arguments.callee est obsolète et est carrément interdit en mode ssortingct ES5. Par conséquent, MDN conseille:

Evitez d’utiliser arguments.callee() en donnant un nom aux expressions de fonction ou en utilisant une déclaration de fonction où une fonction doit s’appeler.

(emphase le mien)

Si une fonction est spécifiée comme expression de fonction, un nom peut lui être atsortingbué.

Il ne sera disponible que dans la fonction (sauf IE8-).

Ce nom est destiné à un appel de fonction récursif fiable, même s’il est écrit dans une autre variable.

Notez qu’avec la déclaration de fonction, cela ne peut pas être fait. Ce nom de fonction interne “spécial” est spécifié uniquement dans la syntaxe Expression de fonction.

 var f = function sayHi(name) { alert( sayHi ); // Inside the function you can see the function code }; alert( sayHi ); // (Error: undefined variable 'sayHi') 

En outre, le nom NFE (Named Function Expression) ne peut pas être remplacé:

 var test = function sayHi(name) { sayHi = "тест"; // try to redefine alert( sayHi ); // function... (redefinition is unsuccessful ) }; test(); 

Utiliser des expressions de fonctions nommées est préférable lorsque vous souhaitez pouvoir référencer la fonction en question sans avoir à vous fier à des fonctionnalités obsolètes telles que arguments.callee .

Vous devez toujours utiliser les expressions de fonction NAMED.

  1. Vous pouvez utiliser le nom de cette fonction lorsque vous avez besoin de récursivité.

2.Les fonctions anonymes ne sont pas utiles lors du débogage, car vous ne pouvez pas voir le nom de la fonction qui pose problème.

3.Lorsque vous ne nommez pas une fonction, il est plus difficile par la suite de comprendre ce qu’elle fait. Donnez-lui un nom qui facilite la compréhension.

 var foo = function bar() { //some code... }; foo(); bar(); // Error! 

Ici, par exemple, comme la barre de nom est utilisée dans une expression de fonction, elle n’est pas déclarée dans la scope externe. Avec les expressions de fonction nommées, le nom de l’expression de la fonction est inclus dans sa propre scope.