web-dev-qa-db-fra.com

Déclarations de fonctions dans les instructions if / else?

Comment sont gérées les déclarations de fonction?

var abc = '';
if(1 === 0){
    function a(){
        abc = 7;
    }
}else if('a' === 'a'){
    function a(){
        abc = 19;
    }
}else if('foo' === 'bar'){
    function a(){
        abc = 'foo';
    }
} 
a();
document.write(abc); //writes "foo" even though 'foo' !== 'bar'

Cet exemple produit différentes sorties dans Chrome et Firefox. Chrome génère foo tandis que FF génère 19).

47
DC_

Lorsque cette question a été posée, ECMAScript 5 (ES5) était répandu. En mode strict d'ES5, les déclarations de fonctions ne peuvent pas être imbriquées à l'intérieur d'un bloc if comme indiqué dans la question. En mode non strict, les résultats étaient imprévisibles. Différents navigateurs et moteurs ont implémenté leurs propres règles pour gérer les déclarations de fonctions à l'intérieur des blocs.

Depuis 2018, de nombreux navigateurs prennent en charge ECMAScript 2015 (ES2015) dans la mesure où les déclarations de fonctions sont désormais autorisées dans les blocs . Dans un environnement ES2015, une déclaration de fonction à l'intérieur d'un bloc sera portée à l'intérieur de ce bloc. Le code de la question entraînera une erreur de fonction indéfinie car la fonction a est uniquement déclarée dans la portée des instructions if et n'existe donc pas dans la portée globale.

Si vous devez définir une fonction de manière conditionnelle, vous devez utiliser expressions de fonction .

55

De http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/

En javascript, vous avez la déclaration de fonction:

function foo() {
}

et expression de fonction

var foo = function() {
}

Citant de http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting

"Les déclarations de fonction et les variables de fonction sont toujours déplacées (" hissées ") en haut de leur portée JavaScript par l'interpréteur JavaScript".

Donc, ce qui s'est passé dans votre premier exemple, c'est que la déclaration de fonction de function a(), est hissée en haut de la portée Javascript, produisant ainsi 'foo' même si le if est évalué à false

Considérez var foo Comme une instruction Javascript normale, elle n'est exécutée que pendant l'exécution de votre javascript, contrairement à function foo(), c'est pourquoi ce qui suit est valide:

alert(foo());

function foo() {
   return 'gw ganteng';
}

Ici, function foo() est analysé par l'analyseur, mettant foo() dans la portée actuelle, avant d'essayer d'appeler alert(foo())

http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/

Dans l'exécution JavaScript, il y a Context (que ECMA 5 décompose en LexicalEnvironment, VariableEnvironment et ThisBinding) et Process (un ensemble d'instructions à invoquer en séquence). Les déclarations contribuent à VariableEnvironment lorsque la portée d'exécution est entrée. Ils sont distincts des déclarations (comme le retour) et ne sont pas soumis à leurs règles de procédure.

7
Andreas Wong

L'ECMA-262 v5 nécessite des implémentations pour enregistrer toutes les déclarations de fonctions et de variables lors de la première passe lors de la saisie de tout nouveau contexte d'exécution global ou de niveau fonction. Chrome le fait techniquement ici car il regarde à l'intérieur des blocs else et then et enregistre a() avant l'exécution. Malheureusement il produit les résultats les plus illisibles.

FF attend jusqu'à ce qu'il évalue l'instruction if avant d'évaluer et d'ajouter des déclarations de fonction et de variable au contexte actuel. BTW. Les deux navigateurs le font de cette façon dans les clauses catch et finally.

Il s'agit vraiment de deux implémentations ECMA différentes traitant d'une fonctionnalité qui ne devrait pas être là pour commencer. Le scénario présenté montre pourquoi les déclarations de fonction ne doivent pas être à l'intérieur des instructions de flux de contrôle.

1
drankin2112