98 votes

Pourquoi utiliser des expressions de fonctions nommées ?

Il existe deux façons différentes d'exprimer des fonctions en JavaScript :

Expression de fonctions nommées (ENF) :

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 vois vraiment pas 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 les deux ?

94voto

T.J. Crowder Points 285826

Dans le cas de l'expression de fonction anonyme, la fonction est anonyme  - littéralement, il n'a pas de nom. La variable à laquelle vous l'assignez a un nom, mais la fonction n'en a pas. (Mise à jour : c'était vrai jusqu'à ES5. Depuis ES2015 [alias ES6], il arrive souvent qu'une fonction créée avec une expression anonyme reçoive un vrai nom [mais pas un identifiant automatique], lisez la suite...)

Les noms sont utiles. Les noms peuvent être vus dans les traces de pile, les piles d'appels, les listes de points d'arrêt, etc. Les noms sont une bonne chose™.

(Il fallait auparavant se méfier des expressions de fonctions nommées dans les anciennes versions d'IE [IE8 et inférieur], car elles créaient par erreur deux objets fonctionnels complètement distincts à deux moments complètement différents [plus d'informations dans mon article de blog Double prise ]. Si vous devez prendre en charge IE8 [ !!], il est probablement préférable de s'en tenir aux expressions de fonctions anonymes ou aux fonctions déclarations mais évitez les expressions de fonctions nommées).

Un élément clé d'une expression de fonction nommée est qu'elle crée un identifiant de portée avec ce nom pour la fonction dans le corps de la fonction :

var x = function example() {
    console.log(typeof example); // "function"
};
x();
console.log(typeof example);     // "undefined"

Depuis ES2015, cependant, de nombreuses expressions de fonctions "anonymes" créent des fonctions avec des noms, et cela a été précédé par divers moteurs JavaScript modernes qui sont assez intelligents pour déduire les noms du contexte. Dans l'ES2015, votre expression de fonction anonyme donne lieu à une fonction portant le nom de boo . Cependant, même avec la sémantique ES2015+, l'identifiant automatique n'est pas créé :

var obj = {
    x: function() {
       console.log(typeof x);   // "undefined"
       console.log(obj.x.name); // "x"
    },
    y: function y() {
       console.log(typeof y);   // "function"
       console.log(obj.y.name); // "y"
    }
};
obj.x();
obj.y();

L'affectation du nom de la fonction se fait avec la fonction SetFunctionName opération abstraite utilisée dans diverses opérations de la spécification.

En résumé, chaque fois qu'une expression de fonction anonyme apparaît sur le côté droit d'une affectation ou d'une initialisation, par exemple :

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

(ou cela pourrait être let ou const plutôt que var ) ou

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

ou

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

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

Il y a une exception importante et intentionnelle : L'assignation à une propriété d'un objet existant :

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

Cela s'explique par les problèmes de fuite d'informations soulevés lorsque la nouvelle fonctionnalité était en cours d'ajout ; détails dans ma réponse à une autre question. aquí .

26voto

Mark Amery Points 4705

Donner un nom aux fonctions est utile si elles doivent se référencer elles-mêmes (par exemple pour les appels récursifs). En effet, si vous passez une expression de fonction littérale comme argument directement à une autre fonction, cette expression de fonction ne peut pas se référer directement à lui-même en mode strict ES5, sauf s'il est nommé.

Par exemple, considérez ce code :

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

Il serait impossible d'écrire ce code de manière aussi propre si l'expression de la fonction transmise à setTimeout étaient anonymes ; nous devrions l'assigner à une variable à la place, avant que l'option setTimeout appel. Cette méthode, 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 déprécié, et est carrément interdit en mode strict ES5. D'où le conseil du MDN :

Évitez d'utiliser arguments.callee() soit par donner un nom aux expressions de fonction ou utiliser une déclaration de fonction où une fonction doit s'appeler elle-même.

(c'est moi qui souligne)

4voto

Antero Ukkonen Points 81

Vous devez toujours utiliser le nom des expressions de fonctions, voilà pourquoi :

  1. Vous pouvez utiliser le nom de cette fonction lorsque vous avez besoin d'une récursion.

  2. Les fonctions anonymes ne sont d'aucune utilité 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. Lui donner un nom permet de mieux le comprendre.

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

    foo(); bar(); // Error!

Ici, par exemple, comme le nom bar est utilisé dans une expression de fonction, il n'est pas déclaré dans la portée externe. Avec les expressions de fonctions nommées, le nom de l'expression de fonction est inclus dans sa propre portée.

3voto

Roman Points 1983

Si une fonction est spécifiée comme une expression de fonction, on peut lui donner un nom.

Il ne sera disponible qu'à l'intérieur de la fonction (sauf IE8-).

var f = function sayHi(name) {
  alert( sayHi ); // Inside the function you can see the function code
};

alert( sayHi ); // (Error: undefined variable 'sayHi')

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

En outre, le nom de l'ENF (expression de fonction nommée) PEUT être écrasé par le nom de l'utilisateur. Object.defineProperty(...) comme suit :

var test = function sayHi(name) {
  Object.defineProperty(test, 'name', { value: 'foo', configurable: true });
  alert( test.name ); // foo
};

test();

Remarque : cela n'est pas possible avec la déclaration de fonction. Ce nom de fonction interne "spécial" est spécifié uniquement dans la syntaxe de l'expression de fonction.

1voto

Sudhir Points 50854

L'utilisation d'expressions de fonctions nommées est préférable, lorsque vous voulez être en mesure de référencer la fonction en question sans avoir à compter sur des fonctionnalités obsolètes telles que arguments.callee .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X