web-dev-qa-db-fra.com

ECMAScript 2015: const dans les boucles

Lequel des fragments de code ci-dessous (ou l'un/l'autre/deux) devrait fonctionner dans une implémentation complète d'ECMAScript 2015:

for (const e of a)

for (const i = 0; i < a.length; i += 1)

À ma connaissance, le premier exemple devrait fonctionner car e est initialisé à chaque itération. Cela ne devrait-il pas également en être de même pour i dans la deuxième version?

Je suis confus parce que les implémentations existantes (Babel, IE, Firefox, Chrome, ESLint) ne semblent pas cohérentes et ont une implémentation complète de const, avec différents comportements des deux variantes de boucle; Je ne parviens pas non plus à trouver un élément concret dans la norme, ce qui serait donc très apprécié.

66
adrianp

La boucle for-of suivante fonctionne:

for (const e of a)

La spécification ES6 décrit ceci comme:

ForDeclaration: LetOrConst ForBinding

http://www.ecma-international.org/ecma-262/6.0/index.html#sec-for-in-and-for-of-statements-static-semantics-boundnames

L'impératif pour la boucle ne fonctionnera pas:

for (const i = 0; i < a.length; i += 1)

En effet, la déclaration n'est évaluée qu'une fois avant que le corps de la boucle ne soit exécuté.

http://www.ecma-international.org/ecma-262/6.0/index.html#sec-for-statement-runtime-semantics-labelledevaluation

81
lyschoening

Je ne citerai pas les spécifications cette fois-ci, car je pense qu'il est plus facile de comprendre ce qui se passe par exemple.

for (const e of a) …

Est fondamentalement équivalent à

{
    const __it = a[Symbol.iterator]();
    let __res;
    while ((__res = __it.next()) && !__res.done) {
        const e = __res.value;
        …
    }
}

Pour simplifier, j’ignore qu’il existe un fichier TDZ avec e pour l’expression a et que les divers __it.return()/__it.throw(e) appellent dans le cas où La boucle se ferme prématurément (break ou throw dans le corps).

for (const i = 0; i < a.length; i += 1) …

est fondamentalement équivalent à

{
    const i = 0;
    while (i < a.length) {
        …
        i += 1;
    }
}

Contrairement à let , une déclaration const dans une boucle for ne sera pas redéclarée à chaque itération de la boucle (et l'initialiseur ne exécuté quand même). Sauf si vous break dans la première itération, votre i += Jettera ici.

35
Bergi

Votre deuxième exemple ne devrait certainement pas fonctionner car i est déclaré une fois et non à chaque itération, il ne s'agit que d'une fonction du fonctionnement de cette catégorie de boucles.

Vous pouvez essayer ceci dans un navigateur classique:

for (var i = 0, otherVar = ""; i < [1,2,3,4].length; i += 1){
  console.log(otherVar)
  otherVar = "If otherVar was initialized on each iteration, then you would never read me.";
}

Ce n'est pas le cas que const soit totalement interdit dans les boucles for. Seul for qui modifiera const est.

Ce sont valables:

for(const i = 0;;){ break } 
for(const i = 0; i < 10;){ break; } 

Ceux-ci sont invalides:

for(const i = 0;;){ ++i; break; } 
for(const i = 0;;++i){ if(i > 0) break; }

Je ne suis pas sûr de savoir pourquoi Firefox donne une SyntaxError après avoir lu la spécification ES2015 (même si je suis sûr que les gens intelligents de Mozilla ont raison), il semble que cela soit supposé lever une exception:

Créez une nouvelle liaison immuable mais non initialisée dans un enregistrement d'environnement. La valeur de chaîne N est le texte du nom lié. Si S est vrai, toute tentative d'accès à la valeur de la liaison avant son initialisation ou sa définition après initialisation générera toujours une exception, quel que soit le paramètre de mode strict des opérations faisant référence à cette liaison. S est un paramètre facultatif dont la valeur par défaut est false.

3
Kit Sunde