Je me souviens que lors d'un entretien en tant que stagiaire chez Tencent, l'intervieweur m'a posé cette question.
Au début, je ne connaissais que deux méthodes de déclaration : la déclaration de fonction et l'expression de fonction. Je ne pouvais pas expliquer les différences spécifiques. Il m'est arrivé de voir récemment un livre sur ce sujet et je voulais le résumer.
Dans ECMAScript, il existe deux méthodes les plus couramment utilisées pour créer des objets fonction, à savoir l'utilisation d'expressions de fonction ou l'utilisation de déclarations de fonction. À cet égard, la spécification ECMAScript indique clairement que la déclaration de fonction doit toujours avoir un identifiant (Identifier), qui est ce que nous appelons le nom de la fonction, et que l'expression de la fonction peut être omise.
Déclaration de fonction :
1. Créez un nouvel objet Function, FormalParameterList spécifie les paramètres et FunctionBody spécifie le corps de la fonction. Utilise la chaîne de portées dans l'environnement en cours d'exécution comme portée.
2. Créez un attribut nommé Identifiant pour l'objet variable actuel, avec la valeur Result(1).
Expression de fonction :
(Les expressions de fonction sont divisées en expressions de fonction anonymes et nommées)
Le processus d'analyse des expressions de fonctions nommées est le suivant :
1. Créer un nouvel objet
2. Ajoutez Result(1) en haut de la chaîne de portée
3. Créez un nouvel objet Function, spécifiez les paramètres dans FormalParameterList et spécifiez le corps de la fonction dans FunctionBody. Utilise la chaîne de portées dans l'environnement d'exécution en cours d'exécution comme portée.
4. Créez un attribut nommé Identifiant pour Result(1), sa valeur est Result(3), en lecture seule, ne peut pas être supprimé
5. Supprimez Result(1)
de la chaîne de portée
6. Retour du résultat (3)
La documentation officielle est très difficile à lire. En termes simples, ECMAScript distingue les deux selon le contexte : si la fonction foo(){} fait partie d'une expression d'affectation, elle est considérée comme une expression de fonction. Et si la fonction foo(){} est contenue dans le corps d'une fonction ou est située dans (le niveau supérieur du) programme, elle est analysée comme une déclaration de fonction. Bien évidemment, lorsque l'identifiant est omis, « l'expression » ne peut être qu'une expression.
Il existe une autre situation :
Ce cas est également une expression de fonction, qui est une fonction entourée d'une paire de parenthèses, () constitue un opérateur de regroupement, et l'opérateur de regroupement ne peut contenir que des expressions.
Parlons brièvement des similitudes et des différences entre les déclarations de fonction et les expressions de fonction. Il existe une différence subtile mais importante dans le comportement des déclarations et des expressions.
Tout d'abord, les déclarations de fonction sont analysées et évaluées avant que les expressions ne soient analysées et évaluées. Même si la déclaration est la dernière ligne du code source, elle sera évaluée avant la première expression dans la même portée. C'est plus facile à comprendre en regardant un exemple. Dans l'exemple suivant, la fonction fn est déclarée après alerte. Cependant, lorsque l'alerte est exécutée, fn est déjà défini :
Pour résumer brièvement, quelle est la différence ?
1. Les déclarations sont toujours analysées au début de la portée
2. Les expressions sont évaluées uniquement lorsqu'elles sont rencontrées.
La déclaration de fonction a une autre caractéristique importante, c'est-à-dire que le comportement de contrôle de la déclaration de fonction via des instructions conditionnelles n'est pas standardisé, donc différents résultats peuvent être obtenus dans différents environnements. C'est à dire :
Alors, quelles sont les règles réelles d'utilisation des déclarations de fonctions ?
FunctionDeclaration ne peut apparaître que dans Program ou FunctionBody. Syntaxiquement, ils ne peuvent pas apparaître à l'intérieur d'un bloc ({ ... }), par exemple dans une instruction if, while ou for. Parce que Block ne peut contenir que des Statement, mais pas des SourceElement tels que FunctionDeclaration.
D'un autre côté, si vous regardez de plus près les règles de génération, vous constaterez que la seule façon pour une Expression d'apparaître dans un Block est de l'intégrer à un ExpressionStatement. Cependant, la spécification indique clairement que ExpressionStatement ne peut pas commencer par le mot-clé function. Cela signifie en réalité que FunctionExpression ne peut pas apparaître dans Statement ou Block (n'oubliez pas que Block est composé de Statement).
En raison des restrictions ci-dessus, chaque fois qu'une fonction apparaît dans un bloc (comme dans l'exemple ci-dessus), elle doit en fait être traitée comme une erreur de syntaxe plutôt que comme une déclaration ou une expression de fonction.
Alors, quand devrions-nous utiliser des déclarations de fonction ou des expressions de fonction ? Les déclarations de fonction ne peuvent apparaître que dans le « code de programme », ce qui signifie qu'elles ne peuvent apparaître que dans d'autres corps de fonction ou dans l'espace global ; leurs définitions ne peuvent pas être affectées à une variable ou à un attribut, ni transmises en tant que paramètre dans un appel de fonction ; Un exemple est l'utilisation autorisée des déclarations de fonction. foo(), bar() et local() sont toutes déclarées via le mode de déclaration de fonction :
Lorsque vous ne pouvez pas utiliser syntaxiquement une déclaration de fonction, vous pouvez utiliser une expression de fonction. Par exemple : passer une fonction en paramètre ou définir une fonction dans un objet littéral :
Mes connaissances sont limitées, merci de me corriger s'il y a des erreurs.