12 juin 2023

Fonctions Expressions

En JavaScript, une fonction n’est pas une “structure de langage magique”, mais un type de valeur particulier.

La syntaxe utilisĂ©e prĂ©cĂ©demment s’appelle une dĂ©claration de fonction :

function sayHi() {
  alert( "Hello" );
}

Il existe une autre syntaxe pour créer une fonction appelée Expression de Fonction.

Cela nous permet de crĂ©er une nouvelle fonction au milieu de n’importe quelle expression.

Par exemple :

let sayHi = function() {
  alert( "Hello" );
};

Ici, nous pouvons voir une variable sayHi obtenir une valeur, la nouvelle fonction, créée en tant que function() { alert("Hello"); }.

Comme la crĂ©ation de la fonction se produit dans le contexte de l’expression d’affectation (Ă  droite de =), il s’agit d’une Fonction Expression.

Veuillez noter qu’il n’y a pas de nom aprĂšs le mot clĂ© function. L’omission d’un nom est autorisĂ©e pour les fonctions expressions.

Ici, nous l’assignons immĂ©diatement Ă  la variable, donc la signification de ces exemples de code est la mĂȘme : “crĂ©er une fonction et la mettre dans la variable sayHi”.

Dans des situations plus avancĂ©es, que nous verrons plus tard, une fonction peut ĂȘtre créée et immĂ©diatement appelĂ©e ou planifiĂ©e pour une exĂ©cution ultĂ©rieure, non stockĂ©e nulle part, restant ainsi anonyme.

La fonction est une valeur

Répétons-le : quelle que soit la maniÚre dont la fonction est créée, une fonction est une valeur. Les deux exemples ci-dessus stockent une fonction dans la variable sayHi.

La signification de ces exemples de code est la mĂȘme : “crĂ©er une fonction et la placer dans la variable sayHi”.

Nous pouvons mĂȘme afficher cette valeur en utilisant alert :

function sayHi() {
  alert( "Hello" );
}

alert( sayHi ); // affiche le code de la fonction

Veuillez noter que la derniĂšre ligne n’exĂ©cute pas la fonction, car il n’y a pas de parenthĂšses aprĂšs sayHi. Il y a des langages de programmation oĂč toute mention d’un nom de fonction provoque son exĂ©cution, mais JavaScript n’est pas comme ça.

En JavaScript, une fonction est une valeur, nous pouvons donc la traiter comme une valeur. Le code ci-dessus montre sa représentation sous forme de chaßne de caractÚres, qui est le code source.

Certes, une fonction est une valeur spĂ©ciale, en ce sens que nous pouvons l’appeler comme cela sayHi().

Mais c’est toujours une valeur. Nous pouvons donc travailler avec comme avec d’autres types de valeurs.

Nous pouvons copier une fonction dans une autre variable :

function sayHi() {   // (1) créer
  alert( "Hello" );
}

let func = sayHi;    // (2) copier

func(); // Hello     // (3) exécuter la copie (ça fonctionne)!
sayHi(); // Hello    //     cela fonctionne toujours aussi (pourquoi pas)

Voici ce qui se passe ci-dessus en détail :

  1. La Déclaration de Fonction (1) crée la fonction et la place dans la variable nommée sayHi.
  2. La ligne (2) la copie dans la variable func. Veuillez noter Ă  nouveau : il n’y a pas de parenthĂšses aprĂšs sayHi. S’il y en avait, alors func = sayHi() Ă©crirait le rĂ©sultat de l’appel sayHi() dans func, et non la fonction sayHi elle-mĂȘme.
  3. Maintenant, la fonction peut ĂȘtre appelĂ©e Ă  la fois en tant que sayHi() et func().

Nous aurions aussi pu utiliser une Fonction Expression pour déclarer sayHi, à la premiÚre ligne :

let sayHi = function() { // (1) create
  alert( "Hello" );
};

let func = sayHi;
// ...

Tout fonctionnerait de la mĂȘme maniĂšre.

Pourquoi y a-t-il un point-virgule Ă  la fin ?

Il peut y avoir une question, pourquoi la Fonction Expression a un point-virgule ; à la fin, et la Fonction Déclaration non :

function sayHi() {
  // ...
}

let sayHi = function() {
  // ...
};

La rĂ©ponse est simple : une expression de fonction est créée ici en tant que function(
) {
} Ă  l’intĂ©rieur de l’instruction d’affectation : let sayHi = 
;. Le point-virgule ; est recommandĂ© Ă  la fin de l’instruction, il ne fait pas partie de la syntaxe de la fonction.

Le point-virgule serait là pour une affectation plus simple, telle que let sayHi = 5;, et il est également là pour une affectation de fonction.

Fonctions callback (de rappel)

Examinons plus d’exemples de fonctions passĂ©es en tant que valeurs et utilisant des expressions de fonction.

Nous allons écrire une fonction ask(question, yes, no) avec trois paramÚtres :

question
Texte de la question
yes
Fonction Ă  exĂ©cuter si la rĂ©ponse est “Yes”
no
Fonction Ă  exĂ©cuter si la rĂ©ponse est “No”

La fonction doit poser la question et, en fonction de la rĂ©ponse de l’utilisateur, appeler yes() ou no() :

function ask(question, yes, no) {
  if (confirm(question)) yes();
  else no();
}

function showOk() {
  alert( "You agreed." );
}

function showCancel() {
  alert( "You canceled the execution." );
}

// utilisation: les fonctions showOk, showCancel sont transmises en tant qu'arguments Ă  ask
ask("Do you agree?", showOk, showCancel);

En pratique, ces fonctions sont trĂšs utiles. La principale diffĂ©rence entre une demande rĂ©elle (ask) et l’exemple ci-dessus est que les fonctions rĂ©elles utilisent des moyens d’interagir avec l’utilisateur plus complexes que la simple confirmation (confirm). Dans le navigateur, une telle fonction dessine gĂ©nĂ©ralement une belle fenĂȘtre de questions. Mais c’est une autre histoire.

Les arguments showOk et showCancel de ask s’appellent des fonctions callback (fonctions de rappel) ou simplement des callbacks (rappels).

L’idĂ©e est que nous passions une fonction et attendions qu’elle soit “rappelĂ©e” plus tard si nĂ©cessaire. Dans notre cas, showOk devient le rappel pour la rĂ©ponse “oui” et showCancel pour la rĂ©ponse “non”.

Nous pouvons utiliser les Fonctions Expressions pour Ă©crire la mĂȘme fonction mais plus courte :

function ask(question, yes, no) {
  if (confirm(question)) yes();
  else no();
}

ask(
  "Do you agree?",
  function() { alert("You agreed."); },
  function() { alert("You canceled the execution."); }
);

Ici, les fonctions sont dĂ©clarĂ©es directement dans l’appel ask(...). Elles n’ont pas de nom et sont donc appelĂ©es anonymes. De telles fonctions ne sont pas accessibles en dehors de ask (car elles ne sont pas affectĂ©es Ă  des variables), mais c’est exactement ce que nous voulons ici.

Ce genre de code apparaüt dans nos scripts trùs naturellement, c’est dans l’esprit de JavaScript.

Une fonction est une valeur reprĂ©sentant une “action”

Des valeurs réguliÚres telles que des chaßnes de caractÚres ou des nombres représentent les données.

Une fonction peut ĂȘtre perçue comme une action.

Nous pouvons tout aussi bien la passer en tant que variable ou l’exĂ©cuter si nous le voulons.

Fonction Expression vs Fonction Déclaration

Formulons les principales différences entre les déclarations de fonction et les expressions de fonctions.

Tout d’abord, la syntaxe : comment les diffĂ©rencier dans le code.

  • La Fonction DĂ©claration une fonction dĂ©clarĂ©e sĂ©parĂ©ment dans le flux de code principal.

    // Function Declaration
    function sum(a, b) {
      return a + b;
    }
  • La Fonction Expression : une fonction créée dans une expression ou dans une autre construction de syntaxe. Ici, la fonction est créée Ă  droite de “l’affectation de l’expression” = :

    // Function Expression
    let sum = function(a, b) {
      return a + b;
    };

La différence la plus subtile est quand une fonction est créée par le moteur JavaScript.

Une Fonction Expression est créée lorsque l’exĂ©cution l’atteint.

Une fois que le flux d’exĂ©cution passe Ă  droite de l’affectation, let sum = function
 , la fonction est créée et peut dĂ©sormais ĂȘtre utilisĂ©e (assignĂ©e, appelĂ©e, etc.).

Les déclarations de fonction sont différentes.

Une Fonction DĂ©claration peut ĂȘtre appelĂ©e plus tĂŽt que sa dĂ©finition.

Par exemple, une fonction dĂ©claration globale est visible dans tout le script, peu importe oĂč elle se trouve.

Cela est dĂ» aux algorithmes internes. Lorsque JavaScript se prĂ©pare Ă  exĂ©cuter le script, il recherche d’abord les fonctions dĂ©clarations globales et les crĂ©e. Nous pouvons considĂ©rer cela comme une â€œĂ©tape d’initialisation”.

Une fois que toutes les déclarations de fonctions ont été traitées, le reste du code est exécuté. Ainsi, il a accÚs à ces fonctions pour les appeler.

Par exemple, cela fonctionne :

sayHi("John"); // Hello, John

function sayHi(name) {
  alert( `Hello, ${name}` );
}

La déclaration de fonction sayHi est créée lorsque JavaScript est sur le point de démarrer le script et est visible partout dans celui-ci.


 S’il s’agissait d’une Fonction Expression, cela ne fonctionnerait pas :

sayHi("John"); // erreur!

let sayHi = function(name) {  // (*) plus de magie
  alert( `Hello, ${name}` );
};

Les expressions de fonction sont créées lorsque l’exĂ©cution les atteint. Cela ne se produirait que dans la ligne (*). Trop tard.

Une autre particularité des Fonctions Declaration est leur portée de bloc.

En mode strict, quand une Fonction Déclaration se trouve dans un bloc de code, elle est visible partout dans ce bloc. Mais pas en dehors.

Par exemple, imaginons que nous ayons besoin de dĂ©clarer une fonction welcome() en fonction de la variable d’age obtenue lors de l’exĂ©cution. Et ensuite, nous prĂ©voyons de l’utiliser quelque temps plus tard.

Si nous utilisons la fonction déclaration, cela ne fonctionnera pas comme prévu :

let age = prompt("Quel est votre age ?", 18);

// déclarer conditionnellement une fonction
if (age < 18) {

  function welcome() {
    alert("Hello!");
  }

} else {

  function welcome() {
    alert("Greetings!");
  }

}

// ...l'utiliser plus tard
welcome(); // Error: welcome is not defined

C’est parce qu’une dĂ©claration de fonction n’est visible que dans le bloc de code dans lequel elle rĂ©side.

Voici un autre exemple :

let age = 16; // prendre 16 comme exemple

if (age < 18) {
  welcome();               // \   (exécution)
                           //  |
  function welcome() {     //  |
    alert("Hello!");       //  |  La déclaration de fonction est disponible
  }                        //  |  partout dans le bloc oĂč elle est dĂ©clarĂ©e
                           //  |
  welcome();               // /   (exécution)

} else {

  function welcome() {
    alert("Greetings!");
  }
}

// Ici, nous sommes en dehors des accolades,
// nous ne pouvons donc pas voir les déclarations de fonction faites à l'intérieur de celles-ci.

welcome(); // Error: welcome is not defined

Que pouvons-nous faire pour rendre welcome visible en dehors de if ?

L’approche correcte consisterait Ă  utiliser une expression de fonction et Ă  attribuer welcome Ă  la variable dĂ©clarĂ©e en dehors de if et offrant la visibilitĂ© appropriĂ©e.

Ce code fonctionne comme prévu :

let age = prompt("What is your age?", 18);

let welcome;

if (age < 18) {

  welcome = function() {
    alert("Hello!");
  };

} else {

  welcome = function() {
    alert("Greetings!");
  };

}

welcome(); // ok maintenant

Ou nous pourrions simplifier encore davantage en utilisant un opérateur conditionnel ternaire ? :

let age = prompt("What is your age?", 18);

let welcome = (age < 18) ?
  function() { alert("Hello!"); } :
  function() { alert("Greetings!"); };

welcome(); // ok maintenant
Quand choisir la fonction déclaration par rapport à la fonction expression ?

En rĂšgle gĂ©nĂ©rale, lorsque nous devons dĂ©clarer une fonction, la premiĂšre chose Ă  prendre en compte est la syntaxe de la fonction dĂ©claration. Cela donne plus de libertĂ© dans l’organisation de notre code, car nous pouvons appeler de telles fonctions avant qu’elles ne soient dĂ©clarĂ©es.

C’est Ă©galement meilleur pour la lisibilitĂ©, car il est plus facile de rechercher la fonction f(
) {
} dans le code que let f = function(
) {
};. Les fonction dĂ©clarations sont plus “accrocheuses”.


 Mais si une dĂ©claration de fonction ne nous convient pas pour une raison quelconque (nous en avons vu un exemple ci-dessus), alors il convient d’utiliser une Fonction Expression.

Résumé

  • Les fonctions sont des valeurs. Elles peuvent ĂȘtre attribuĂ©es, copiĂ©es ou dĂ©clarĂ©es Ă  n’importe quel endroit du code.
  • Si la fonction est dĂ©clarĂ©e comme une instruction distincte dans le flux de code principal, cela s’appelle une “dĂ©claration de fonction”.
  • Si la fonction est créée dans le cadre d’une expression, elle est appelĂ©e “expression de fonction”.
  • Les dĂ©clarations de fonctions sont traitĂ©es avant l’exĂ©cution du bloc de code. Elles sont visibles partout dans le bloc.
  • Les expressions de fonction sont créées lorsque le flux d’exĂ©cution les atteint.

Dans la plupart des cas, lorsque nous devons dĂ©clarer une fonction, une fonction dĂ©claration est prĂ©fĂ©rable parce qu’elle est visible avant la dĂ©claration elle-mĂȘme. Cela nous donne plus de flexibilitĂ© dans l’organisation du code et il est gĂ©nĂ©ralement plus lisible.

Nous devrions donc utiliser une fonction expression uniquement lorsqu’une fonction dĂ©claration n’est pas adaptĂ©e Ă  la tĂąche. Nous en avons vu quelques exemples dans ce chapitre et nous en verrons d’autres Ă  l’avenir.

Carte du tutoriel

Commentaires

lire ceci avant de commenter

  • Si vous avez des amĂ©liorations Ă  suggĂ©rer, merci de soumettre une issue GitHub ou une pull request au lieu de commenter.
  • Si vous ne comprenez pas quelque chose dans l'article, merci de prĂ©ciser.
  • Pour insĂ©rer quelques bouts de code, utilisez la balise <code>, pour plusieurs lignes – enveloppez-les avec la balise <pre>, pour plus de 10 lignes - utilisez une sandbox (plnkr, jsbin, codepen
)