Selon MDN :
Une expression est toute unité de code valide qui se résout en une valeur.
En tant que tel, tout ce qui peut être utilisé comme une rvalue est une expression.
Le critère est le suivant no si des effets secondaires existent. Les expressions peuvent certainement avoir des effets secondaires. Par exemple a=2
est une expression car elle a une valeur (2) et attribue également une valeur à une variable. C'est pourquoi vous pouvez faire des choses comme :
let a;
let b = 1 + (a = 2); // a is now 2 and b is 3
Il est possible qu'un même bloc de code (textuel) soit considéré à la fois comme une expression y une déclaration en fonction du contexte. Par exemple, l'extrait de texte function f(){}
est une expression à la ligne 1 et une instruction à la ligne 2 dans le code ci-dessous :
let g = function f() {};
function f() {};
Ainsi, il n'est pas possible (dans le cas général) de déterminer si quelque chose est une expression ou une déclaration en examinant un morceau de code textuel hors de son contexte ; il s'agit plutôt d'une propriété d'un nœud dans un arbre syntaxique qui ne peut être déterminée qu'après l'analyse (mentale ou réelle) du code.
En outre, et c'est peut-être plus important, les instructions de fonction (c'est-à-dire les déclarations de fonction) à l'intérieur d'une fonction f
font partie du contexte d'exécution qui est créé lorsque la fonction f
est invoquée. Toutefois, les expressions de fonctions ne no font partie de ce contexte d'exécution.
Un effet souvent cité est que les déclarations de fonctions sont "hissées" alors que les expressions de fonctions ne le sont pas.
Un effet plus subtil peut également être observé expérimentalement dans les récursions profondes, étant donné que les instructions de fonction occupent de l'espace dans le contexte d'exécution alors que les expressions de fonction n'en occupent pas. Par exemple, le code ci-dessous utilise la récursion infinie d'une fonction f
. Fonction f
Dans le premier cas, il contient une expression de fonction, dans le second cas, il contient la déclaration de fonction équivalente :
// Function Expression
{
let i = 0;
try {
function f () {
i++;
(function g() {})(); // this is an expression
f();
}
f();
} catch (err) {
console.log(`Function Expressions case: depth of ${i} reached. Error: ${err.name}`);
}
}
// Function Declaration
{
let i = 0;
try {
function f () {
i++;
function g() {}; // this is a statement
g();
f();
}
f();
} catch (err) {
console.log(`Functions Declarations case: depth of ${i} reached. Error: ${err.name}`);
}
}
Sur ma machine, j'obtiens systématiquement le résultat suivant (en node.js) :
Function Expressions case: depth of 17687 reached. Error: RangeError
Functions Declarations case: depth of 15476 reached. Error: RangeError
ce qui est cohérent avec le fait que les déclarations de fonctions augmentent la quantité d'espace nécessaire pour contenir un contexte d'exécution et consomment donc un peu plus rapidement l'espace de la pile et diminuent ainsi légèrement la profondeur maximale de récursion.