D'abord, je veux corriger Greg : function abc(){}
a également un champ d'application - le nom abc
est définie dans l'étendue où cette définition est rencontrée. Exemple :
function xyz(){
function abc(){};
// abc is defined here...
}
// ...but not here
Deuxièmement, il est possible de combiner les deux styles :
var xyz = function abc(){};
xyz
va être défini comme d'habitude, abc
est indéfini dans tous les navigateurs sauf IE - ne comptez pas sur sa définition. Mais il sera défini à l'intérieur de son corps :
var xyz = function abc(){
// xyz is visible here
// abc is visible here
}
// xyz is visible here
// abc is undefined here
Si vous voulez aliaser des fonctions sur tous les navigateurs, utilisez ce type de déclaration :
function abc(){};
var xyz = abc;
Dans ce cas, les deux xyz
et abc
sont des alias du même objet :
console.log(xyz === abc); // prints "true"
Une raison convaincante d'utiliser le style combiné est l'attribut "name" des objets fonctionnels ( non supporté par IE ). En gros, lorsque vous définissez une fonction comme ceci :
function abc(){};
console.log(abc.name); // prints "abc"
son nom est automatiquement attribué. Mais lorsque vous le définissez comme ceci :
var abc = function(){};
console.log(abc.name); // prints ""
son nom est vide - nous avons créé une fonction anonyme et l'avons assignée à une variable.
Une autre bonne raison d'utiliser le style combiné est d'utiliser un nom interne court pour se référer à lui-même, tout en fournissant un nom long non contradictoire pour les utilisateurs externes :
// assume really.long.external.scoped is {}
really.long.external.scoped.name = function shortcut(n){
// let's call itself recursively:
shortcut(n - 1);
// ...
// let's pass itself as a callback:
someFunction(shortcut);
// ...
}
Dans l'exemple ci-dessus, nous pourrions faire la même chose avec un nom externe, mais ce serait trop lourd (et plus lent).
(Une autre façon de se référer à lui-même est d'utiliser arguments.callee
ce qui est encore relativement long, et n'est pas supporté dans le mode strict).
Au fond, JavaScript traite les deux déclarations différemment. Il s'agit d'une déclaration de fonction :
function abc(){}
abc
ici est défini partout dans la portée actuelle :
// we can call it here
abc(); // works
// yet it is defined down there
function abc(){}
// we can call it again
abc(); // works
Il s'agit d'une expression de fonction :
var xyz = function(){};
xyz
ici est défini à partir du point d'affectation :
// we can't call it here
xyz(); // UNDEFINED!!!
// now it is defined
xyz = function(){}
// we can call it here
xyz(); // works
La déclaration de fonction par rapport à l'expression de fonction est la véritable raison pour laquelle il existe une différence démontrée par Greg.
Fait amusant :
var xyz = function abc(){};
console.log(xyz.name); // prints "abc"
Personnellement, je préfère la déclaration "expression de fonction" car de cette façon, je peux contrôler la visibilité. Quand je définis la fonction comme ça :
var abc = function(){};
Je sais que j'ai défini la fonction localement. Quand je définis la fonction comme ça :
abc = function(){};
Je sais que je l'ai défini globalement à condition que je n'ai pas défini abc
n'importe où dans la chaîne des scopes. Ce style de définition est résilient même lorsqu'il est utilisé à l'intérieur de eval(). Bien que cette définition :
function abc(){};
dépend du contexte et peut vous laisser deviner où il est réellement défini, notamment dans le cas de eval() - la réponse est : cela dépend du navigateur.