web-dev-qa-db-fra.com

Pourquoi puis-je utiliser une fonction avant qu'elle ne soit définie en JavaScript?

Ce code fonctionne toujours, même dans différents navigateurs:

function fooCheck() {
  alert(internalFoo()); // We are using internalFoo() here...

  return internalFoo(); // And here, even though it has not been defined...

  function internalFoo() { return true; } //...until here!
}

fooCheck();

Je n'ai pas pu trouver une seule référence à pourquoi cela devrait fonctionner, cependant. J'ai vu cela pour la première fois dans la note de présentation de John Resig, mais cela n'a été mentionné que. Il n'y a aucune explication là-bas ou nulle part d'ailleurs.

Quelqu'un pourrait-il m'éclairer.

151
Edu Felipe

La déclaration function est magique et oblige son identifiant à être lié avant que quoi que ce soit dans son bloc de code * soit exécuté.

Cela diffère d'une affectation avec une expression function, qui est évaluée dans un ordre descendant normal.

Si vous avez changé l'exemple pour dire:

var internalFoo = function() { return true; };

cela cesserait de fonctionner.

La déclaration de fonction est syntaxiquement assez distincte de l'expression de fonction, même si elles semblent presque identiques et peuvent être ambiguës dans certains cas.

Ceci est documenté dans la section ECMAScript standard 10.1.3 . Malheureusement, l'ECMA-262 n'est pas un document très lisible, même selon les normes-normes!

*: la fonction contenant, bloc, module ou script.

203
bobince

On l'appelle HOISTING - Invoquer (appelé) une fonction avant l'endroit où elle a été définie.

Deux types de fonctions différents sur lesquels je veux écrire sont:

Fonctions d'expression et fonctions de décélération

  1. Fonctions d'expression:

    Une expression de fonction peut être stockée dans une variable afin de ne pas avoir besoin de noms de fonction. Ils seront également nommés comme une fonction anonyme (une fonction sans nom).

    Pour appeler (appelé), il faut toujours utiliser un nom de variable . Ce type de fonctions ne fonctionnera pas si les appels avant où ils ont été définis, ce qui signifie que le levage ne se produit pas ici. Nous devons toujours définir la fonction d'expression d'abord, puis l'invoquer.

    let lastName = function (family) {
     console.log("My last name is " + family);
    };
    let x = lastName("Lopez");
    

    Voici comment vous pouvez écrire dans ECMAScript 6:

    lastName = (family) => console.log("My last name is " + family);
    
    x = lastName("Lopez");
    
  2. Fonctions de décélération:

    Les fonctions déclarées avec la syntaxe suivante ne sont pas exécutées immédiatement. Ils sont "enregistrés pour une utilisation ultérieure" et seront exécutés ultérieurement, lorsqu'ils seront invoqués (appelés). Ces types de fonctions fonctionnent si vous les appelez AVANT ou APRÈS où elles ont été définies. Si vous appelez une fonction de décélération avant l'endroit où elle a été définie - Levage - fonctionne correctement.

    function Name(name) {
      console.log("My cat's name is " + name);
    }
    Name("Chloe");
    

    Exemple de levage:

    Name("Chloe");
    function Name(name) {
       console.log("My cat's name is " + name);
    }
    
19
Negin

Le navigateur lit votre code HTML du début à la fin et peut l'exécuter tel qu'il est lu et analysé en morceaux exécutables (déclarations de variables, définitions de fonctions, etc.) Mais à tout moment ne peut utiliser que ce qui a été défini dans le script avant ce point.

Ceci est différent des autres contextes de programmation qui traitent (compilent) tout votre code source, peut-être le lient avec toutes les bibliothèques dont vous avez besoin pour résoudre les références et construisent un module exécutable, auquel point l'exécution commence.

Votre code peut faire référence à des objets nommés (variables, autres fonctions, etc.) qui sont définis plus loin, mais vous ne pouvez pas exécuter de code de référence tant que toutes les pièces ne sont pas disponibles.

À mesure que vous vous familiariserez avec JavaScript, vous deviendrez intimement conscient de votre besoin d'écrire les choses dans le bon ordre.

Révision: Pour confirmer la réponse acceptée (ci-dessus), utilisez Firebug pour parcourir la section de script d'une page Web. Vous le verrez sauter de fonction en fonction, ne visitant que la première ligne, avant d'exécuter réellement du code.

13
dkretz

Certaines langues exigent que les identifiants soient définis avant utilisation. Une raison à cela est que le compilateur utilise un seul passage sur le code source.

Mais s'il y a plusieurs passes (ou certains contrôles sont reportés), vous pouvez parfaitement vivre sans cette exigence. Dans ce cas, le code est probablement d'abord lu (et interprété), puis les liens sont définis.

3
Toon Krijthe

Je n'ai utilisé que peu de JavaScript. Je ne sais pas si cela vous aidera, mais cela ressemble beaucoup à ce dont vous parlez et peut donner un aperçu:

http://www.dustindiaz.com/javascript-function-declaration-ambiguity/

2
RailsSon

Le corps de la fonction "internalFoo" doit aller quelque part au moment de l'analyse, donc lorsque le code est lu (par exemple l'analyse) par l'interpréteur JS, la structure de données de la fonction est créée et le nom est attribué.

Ce n'est que plus tard, que le code est exécuté, JavaScript essaie en fait de savoir si "internalFoo" existe et ce qu'il est et s'il peut être appelé, etc.

0
Aaron Digulla