Nouveautés dans JavaScript 1.7

  • Raccourci de la révision : Nouveautés_dans_JavaScript_1.7
  • Titre de la révision : Nouveautés dans JavaScript 1.7
  • ID de la révision : 280882
  • Créé :
  • Créateur : BenoitL
  • Version actuelle ? Non
  • Commentaire début de mise à jour (les derniers exemples doivent encore être refaits)

Contenu de la révision

JavaScript 1.7 est une mise à jour du langage qui introduit plusieurs nouvelles fonctionnalités, en particulier : des générateurs et des itérateurs, la définition de tableaux par compréhension, les expressions let et l'assignation déstructurante. Il reprend également toutes les fonctionnalités de JavaScript 1.6.

JavaScript 1.7 est disponible à partir de Firefox 2 bêta 1, ainsi que sur le tronc (Minefield).

Les exemples de code fournis dans cet article peuvent être essayés dans le shell JavaScript. Consultez Introduction au shell JavaScript pour apprendre comment mettre en place et utiliser le shell.

Utilisation de JavaScript 1.7

Afin de pouvoir utiliser les nouvelles fonctionnalités de JavaScript 1.7, il est nécessaire de spécifier qu'on utilise JavaScript 1.7. Dans du code HTML ou XUL, on utilisera :

<script type="application/javascript;version=1.7"/>

Si vous utilisez le shell JavaScript, vous devrez définir la version utilisée à l'aide de la fonction version() :

version(170);

Générateurs et itérateurs

Au cours du développement de code utilisant un algorithme itératif (comme le parcours d'une liste, ou des calculs répétitifs sur le même jeu de données), on rencontre souvent des variables d'état dont les valeurs doivent être conservées tout au long du processus de calcul. Traditionnellement, on utilise une fonction de callback pour obtenir les valeurs intermédiaires d'un algorithme itératif.

Générateurs

Prenons cet algorithme itératif calculant les nombres de Fibonacci :

function do_callback(num) {
  document.write(num + "<BR>\n");
}

function fib() {
  var i = 0, j = 1, n = 0;
  while (n < 10) {
    do_callback(i);
    var t = i;
    i = j;
    j += t;
    n++;
  }
}

fib();

Ce code utilise une routine de callback pour réaliser des opérations à chaque étape itérative de l'algorithme. Dans ce cas, chaque nombre de Fibonacci est simplement affiché dans la console.

Les nouveaux générateurs et itérateurs fonctionnent ensemble pour fournir une meilleure manière de faire ceci. Voyons à quoi ressemble la routine des nombres de Fibonacci lorsqu'on utilise un générateur :

function fib() {
  var i = 0, j = 1;
  while (true) {
    yield i;
    var t = i;
    i = j;
    j += t;
  }
}

var g = fib();
for (var i = 0; i < 10; i++) {
  document.write(g.next() + "<BR>\n");
}

La fonction contenant le mot-clé yield est un générateur. Lorsqu'on l'appelle, ses paramètres formels sont liés aux arguments effectifs, mais son corps n'est pas évalué. Au lieu de cela, un générateur-itérateur est renvoyé. Chaque appel à la méthode next() du générateur-itérateur provoque un nouveau passage au travers de l'algorithme itératif. La valeur à chaque étape est celle spécifiée par le mot-clé yield. Pensez à yield comme la version générateur-itérateur de return, indiquant la limite entre chaque itération de l'algorithme. Chaque fois que next() est appelée, le code du générateur reprend à l'instruction suivant le yield.

On cycle dans un générateur-itérateur en appelant à plusieurs reprises sa méthode next() jusqu'à ce que la condition résultante désirée soit atteinte. Dans cet exemple, on peut obtenir autant de nombres de Fibonacci que l'on veut en continuant à appeler g.next() jusqu'à ce que le nombre de résultats voulu soit atteint.

Itérateurs

Un itérateur est un objet spécial qui permet un parcours itératif de données.

Dans leur utilisation normale, les objets itérateurs sont « invisibles » ; il n'est pas nécessaire de les utiliser explicitement, mais on utilisera plutôt les instructions JavaScript for...in et for each...in pour boucler de manière naturelle sur les clés et/ou valeurs des objets.

var objectWithIterator = getObjectSomehow();

for (var i in objectWithIterator)
{
  document.write(objectWithIterator[i] + "<BR>\n");
}

Si vous implémentez votre propre objet itérateur, ou avez besoin pour une autre raison de manipuler des itérateurs, vous devrez connaître la méthode next, l'exception StopIteration et la propriété __iterator__.

On peut créer un itérateur pour un objet en appelant Iterator(nomdobjet) ; l'itérateur d'un objet peut être trouvé en utilisant sa propriété __iterator__, qui par défaut implémente l'itération selon le modèle habituel for...in et for each...in. Si vous voulez fournir un itérateur personnalisé, vous devez écraser l'accesseur pour __iterator__ afin qu'il renvoie une instance de votre itérateur personnalisé. Pour obtenir un itérateur d'objet depuis un script, vous devriez utiliser Iterator(obj) plutôt qu'accéder à la propriété __iterator__ directement.

Une fois l'itérateur obtenu, il est facile de passer à l'élément suivant dans l'objet en appelant la méthode next() de l'itérateur. S'il n'y a plus de donnée à parcourir, l'exception StopIteration est déclenchée.

Voici un exemple simple de manipulation directe d'un itérateur :

var obj = {name:"Jack Bauer", username:"JackB", id:12345, agency:"CTU", region:"Los Angeles"};

var it = Iterator(obj);

try {
  while (true) {
    document.write(it.next() + "<BR>\n");
  }
} catch (err if err instanceof StopIteration) {
  document.write("End of record.<BR>\n");
} catch (err) {
  document.write("Unknown error: " + err.description + "<BR>\n");
}

Le résultat affiché par ce programme ressemble à ceci :

name,Jack Bauer
username,JackB
id,12345
agency,CTU
region,Los Angeles
End of record.

Il est possible, optionnellement, de spécifier un second paramètre à la création de l'itérateur, qui est une valeur booléenne indiquant si seules les clés doivent être renvoyées à chaque fois que la méthode next() est appelée. Si on change var it = Iterator(obj); en var it = Iterator(obj, true); dans l'exemple ci-dessus, on obtient le résultat suivant :

name
username
id
agency
region
End of record.

Dans les deux cas, l'ordre réel dans lequel les données sont renvoyées peut varier selon l'implémentation. Aucun ordre n'est garanti dans les données.

Les itérateurs sont une manière pratique de parcourir les données dans des objets, même les objets qui peuvent contenir des données dont vous ne connaissez pas l'existence. C'est particulièrement utile dans le cas où des données non attendues par votre application doivent toutefois être préservées.

Définition de tableaux par compréhension

Les tableaux définis par compréhension sont une utilisation des générateurs fournissant une manière pratique et puissante d'initialiser des tableaux. Par exemple :

function range(begin, end) {
  for (let i = begin; i < end; ++i) {
    yield i;
  }
}

range() est un générateur renvoyant toutes les valeurs entre <tt>begin</tt> et <tt>end</tt>. Une fois cette fonction définie, on peut l'utiliser comme ceci :

var ten_squares = [i * i for (i in range(0, 10))];

Un nouveau tableau ten_squares est préinitialisé pour contenir les carrés des valeurs dans l'intervalle 0..9.

On peut préciser n'importe quelle condition à l'initialisation du tableau. Si vous voulez initialiser un tableau pour contenir les nombres pairs entre 0 et 20, vous pouvez utiliser ce code :

var evens = [i for (i in range(0, 21)) if (i % 2 == 0)];

Avant JavaScript 1.7, il aurait été nécessaire d'écrire quelque chose de semblable à ceci :

var evens = [];
for (var i=0; i <= 20; i++) {
  if (i % 2 == 0)
    evens.push(i);
}

La notation par compréhension est non seulement plus compacte, mais elle est également plus facile à lire une fois familiarisé avec le concept.

Règles de portée

Les définitions de tableaux par compréhension ont un bloc implicite autour d'elles, contenant tout ce qui se trouve entre les crochets droits, ainsi que des déclarations let implicites.

Plus de détails sont nécessaires.

Portée des variables avec let

Il y a plusieurs manières d'utiliser let pour gérer la porté de bloc de données et de fonctions :

  • L'instruction let est une manière d'associer des valeurs avec des variables, constantes et fonctions au sein d'un bloc sans affecter les valeurs de variables portant le même nom en dehors du bloc.
  • L'expression let permet de mettre en place des variables dont la portée se limite à une seule expression.
  • La définition avec let définit des variables, constantes et fonctions dont la portée est limitée au bloc dans lequel elles sont définies. Cette syntaxe est très similaire à celle utilisée avec var.
  • Il est également possible d'utiliser let pour mettre en place des variables existant uniquement dans le contexte d'une boucle for.

L'instruction let

L'instruction let fournit une portée locale pour les variables, constantes et fonctions. Elle fonctionne en liant un ensemble de variables à la portée lexicale d'un seul bloc de code. La valeur de terminaison de l'instruction let est celle du bloc.

Par exemple :

var x = 5;
var y = 0;

let (x = x+10, y = 12) {
  document.write(x+y + "<BR>\n");
}

document.write(x+y + "<BR>\n");

L'affichage produit par ce programme sera :

27
5

Les règles pour le bloc de code sont les mêmes que pour n'importe quel autre bloc de code en JavaScript. Il peut avoir ses propres variables locales déclarées à l'aide de let.

Note : Les parenthèses suivant let sont ici obligatoires. Leur absence résulterait en une erreur de syntaxe.
Règles de portée

La portée des variables définies à l'aide de let est le bloc let lui-même, ainsi que tout bloc interne contenu à l'intérieur de celui-ci, à moins que ces blocs définissent des variables ayant les mêmes noms.

Expressions avec let

On peut utiliser let pour définir des variables dont la portée se limitent à une seule expression :

var x = 5;
var y = 0;
document.write( let(x = x + 10, y = 12) x+y  + "
\n"); document.write(x+y + "
\n");

L'affichage produit est :

27
5

Dans ce cas, la liaison entre les valeurs de x et y, et les expressions x+10 et 12 a une portée limitée uniquement à l'expression x+y.

Règles de portée

Avec une expression let donnée :

let (decls) expr

Un bloc implicite est créé autour de expr.

Définitions avec let

Le mot-clé let peut également être utilisé pour définir des variables, constantes et fonctions au sein d'un bloc.

 ** Ce code dne fonctionne pas dans Firefox 2.0 b1. **
if (x > y)
{
   let const k = 37;
   let gamma : int = 12.7 + k;
   let i = 10;
   let function f(n) { return (n/3)+k; }
   return f(gamma) + f(i);
}
Règles de portée

Les variables, fonctions et constantes déclarées avec let, let function et let const ont leur portée limitée au bloc dans lequel elles sont définies, ainsi que dans tout sous-bloc dans lequel elles ne sont pas redéfinies. Dans ce sens, let fonctionne tout à fait comme var.

Dans les programmes et classes, let ne crée pas de propriétés sur les objets global et de classe comme le ferait var ; au lieu de cela, des propriétés sont créées dans un bloc implicite créé pour l'évaluation des instructions dans ces contextes. Essentiellement, cela signifie que let n'écrasera pas de variables définies précédemment avec var. Par exemple :

** Ne fonctionne pas dans Firefox 2.0 b1. Renvoie "42" au lieu de "global".
var x = 'global';
let x = 42;
document.write(this.x + "
\n");

Ce code affichera « global », et non « 42 ».

Un bloc implicite est un bloc non entouré de crochets ; il est créé implicitement par le moteur JavaScript.

Dans les fonctions, let lorsqu'il est exécuté par eval() ne crée pas de propriétés sur l'objet de la variable (objet d'activation ou de liaison interne) comme var le ferait ; au lieu de cela, des propriétés sont créées dans un bloc implicite créé pour l'évaluation d'instuctions dans le programme. Il s'agit d'une conséquence du comportement d'eval() sur des programmes combiné avec la règle qui précède.

Autrement dit, lorsqu'eval() est utilisé pour exécuter du code, ce code est traité comme un programme indépendant, qui a son propre bloc implicite autour de son code.

Variables déclarées avec let dans des boucles for

Le mot-clé let peut être utilisé pour lier des variables localement dans la portée de boucles for, exactement comme avec var.

   var i=0;
   for ( let i=i ; i < 10 ; i++ )
     document.write(i + "<BR>\n");

   for ( let &[name,value] in obj )
     document.write("Name: " + name + ", Value: " + value + "<BR>\n");
Règles de portée
for (let expr1; expr2; expr3) statement

Dans cet exemple, expr2, expr3 et statement font partie d'un bloc implicite contenant les variables de bloc déclarées avec let expr1. C'est ce qui est montré dans la première boucle ci-dessus.

for (expr1 in expr2) statement

Dans ce cas, un bloc implicite contient statement. C'est ce qui est montré dans la seconde boucle ci-dessus.

Assignation déstructurante

L'assignation déstructurente rend possible l'extraction de données depuis des tableaux ou des objets en utilisant une syntaxe reproduisant celle des déclarations littérales de tableaux et d'objets.

Les expressions littérales d'objet et de tableau forment une manière facile de créer des paquets de données ad-hoc. Une fois ces paquets créés, ils peuvent être utilisés de n'importe quelle manière. Ils peuvent même être renvoyés par des fonctions.

Une application particulièrement utile de l'assignation déstructurée est de lire une structure entière en une seule instruction, bien qu'il y ait un bon nombre d'autre choses intéressantes comme le montrent les exemples développés plus bas.

Cette possibilité est similaire à celles qui sont présentes dans des langages comme Perl et Python.

Exemples

L'assignation déstructurée s'explique le mieux au travers d'exemples, en voici donc quelques uns qui vous permettront de comprendre.

Note : si vous avez des exemples intéressants d'utilisation de l'assignation déstructurée, n'hésitez pas à les ajouter à cette section.
Échange de valeurs

L'assignation déstructurée peut par exemple être utilisée pour échanger des valeurs :

var a = 1;
var b = 3;
[a, b] = [b, a];

Après exécution de ce code, b vaut 1 et a vaut 3.

Renvoi de valeurs multiples

Grâce à l'assignation déstructurante, les fonctions peuvent renvoyer plusieurs valeurs. Bien qu'il ait toujours été possible de renvoyer un tableau, on a ici un degré de flexibilité supplémentaire :


function f() {
  return [1, 2];
}

Comme vous pouvez le voir, le renvoi de résultats se fait à l'aide d'une notation semblable à un tableau, avec toutes les valeurs à renvoyer entourées de crochets droits. N'importe quel nombre de résultats peut être renvoyé de cette manière. Dans cet exemple, f() renvoie les valeurs {{mediawiki.external('1, 2')}}.

var a, b;
[a, b] = f();
document.write ("A vaut " + a + " B vaut " + b + "
\n");

La commande {{mediawiki.external('a, b')}} = f() assigne le résultat de la fonction aux variables entre crochets, dans l'ordre : a est positionnée à 1 et b est positionnée à 2.

Les valeurs de retour peuvent également être récupérées dans un tableau :

var a = f();
document.write ("A is " + a);

Dans ce cas, a est un tableau contenant les valeurs 1 et 2.

Ignorer certaines valeurs renvoyées

Il est également possible d'ignorer les valeurs de retour qui ne vous intéressent pas :

function f() {
  return [1, 2, 3];
}

var [a,, b] = f();
document.write ("A is " + a + " B is " + b + "<BR>\n");

Après exécution de ce code, a vaut 1 et b vaut 3. La valeur 2 est ignorée. Il est possible d'ignorer toute (ou toutes les) valeur(s) renvoyée(s) de cette manière. Par exemple :

[,,,] = f();
Parcours d'objets

L'assignation déstructurante peut également être utilisée pour extraire des données d'un objet :

for (let[name, value] in obj) {
  print("Name: " + name + ", Value: " + value);
}

Ceci récupère les champs name et value d'un objet obj et les affiche.

Parcours des valeurs d'un objet

Il est possible de parcourir les valeur d'un objet de la même manière :

for each (let {name: n, family: { father: f } } in obj) {
  print("Name: " + n + ", Father: " + f);
}

Manque une explication sur ce que cela fait

Capture de lignes et mise à jour d'enregistrements

Liée à l'assignation déstructurante, la capture de lignes permet de récupérer des champs individuels d'une structure, ainsi qu'une nouvelle structure contenant les champs que vous n'avez pas explicitement extraits.

Par exemple :

var personRecord = { name: "Bob", city: "Foohaven", job: "Programmer", employer: "Barco Inc." };

{ name: x, city: y, ...: z } = personRecord;

Ce code extrait les champs name et city dans les variables x et y, respectivement, et crée également une nouvelle structure, z, qui contient { job: "Programmer", employer: "Barco Inc." }.

Une utilisation pratique de cette possibilité est la préservation de données. Si votre code doit être capable de travailler sur des données pouvant contenir des champs dont vous n'avez pas connaissance, vous pouvez extraire les champs inconnus dans une structure pour les préserver même si vous ne connaissez pas leurs noms.

Les valeurs et structures peuvent également être combinées ensemble à l'aide de cette syntaxe. Par exemple, si Bob déménage, il faut changer le champ city dans l'enregistrement ci-dessus. Après cela, l'enregistrement complet peut être reconstruit avec les nouvelles données.

Cela peut se faire très facilement, comme ceci :

var newPersonRecord = { ... = z, city = "New Foohaven" };

Après cela, newPersonRecord contient { name: "Bob", city: "New Foohaven", job: "Programmer", employer: "Barco Inc." }.

En termes simples, « ... » est un raccourci pour « tout champ que je n'ai pas explicitement mentionné. »

{{ wiki.languages( { "en": "en/New_in_JavaScript_1.7", "pl": "pl/Nowo\u015bci_w_JavaScript_1.7" } ) }}

Source de la révision

<p>JavaScript 1.7 est une mise à jour du langage qui introduit plusieurs nouvelles fonctionnalités, en particulier : des générateurs et des itérateurs, la définition de tableaux par compréhension, les expressions <code>let</code> et l'assignation déstructurante. Il reprend également toutes les fonctionnalités de <a href="fr/Nouveaut%c3%a9s_dans_JavaScript_1.6">JavaScript 1.6</a>.
</p><p>JavaScript 1.7 est disponible à partir de <a href="fr/Firefox_2">Firefox 2</a> bêta 1, ainsi que sur le tronc (Minefield).
</p><p>Les exemples de code fournis dans cet article peuvent être essayés dans le shell JavaScript. Consultez <a href="fr/Introduction_au_shell_JavaScript">Introduction au shell JavaScript</a> pour apprendre comment mettre en place et utiliser le shell.
</p>
<h3 name="Utilisation_de_JavaScript_1.7"> Utilisation de JavaScript 1.7 </h3>
<p>Afin de pouvoir utiliser les nouvelles fonctionnalités de JavaScript 1.7, il est nécessaire de spécifier qu'on utilise JavaScript 1.7. Dans du code HTML ou XUL, on utilisera :
</p>
<pre class="eval">&lt;script type="application/javascript;version=1.7"/&gt;
</pre>
<p>Si vous utilisez le shell JavaScript, vous devrez définir la version utilisée à l'aide de la fonction <code>version()</code> :
</p>
<pre class="eval">version(170);
</pre>
<h3 name="G.C3.A9n.C3.A9rateurs_et_it.C3.A9rateurs"> Générateurs et itérateurs </h3>
<p>Au cours du développement de code utilisant un algorithme itératif (comme le parcours d'une liste, ou des calculs répétitifs sur le même jeu de données), on rencontre souvent des variables d'état dont les valeurs doivent être conservées tout au long du processus de calcul. Traditionnellement, on utilise une fonction de callback pour obtenir les valeurs intermédiaires d'un algorithme itératif.
</p>
<h4 name="G.C3.A9n.C3.A9rateurs"> Générateurs </h4>
<p>Prenons cet algorithme itératif calculant les nombres de Fibonacci :
</p>
<pre>function do_callback(num) {
  document.write(num + "&lt;BR&gt;\n");
}

function fib() {
  var i = 0, j = 1, n = 0;
  while (n &lt; 10) {
    do_callback(i);
    var t = i;
    i = j;
    j += t;
    n++;
  }
}

fib();
</pre>
<p>Ce code utilise une routine de callback pour réaliser des opérations à chaque étape itérative de l'algorithme. Dans ce cas, chaque nombre de Fibonacci est simplement affiché dans la console.
</p><p>Les nouveaux générateurs et itérateurs fonctionnent ensemble pour fournir une meilleure manière de faire ceci. Voyons à quoi ressemble la routine des nombres de Fibonacci lorsqu'on utilise un générateur :
</p>
<pre>function fib() {
  var i = 0, j = 1;
  while (true) {
    yield i;
    var t = i;
    i = j;
    j += t;
  }
}

var g = fib();
for (var i = 0; i &lt; 10; i++) {
  document.write(g.next() + "&lt;BR&gt;\n");
}
</pre>
<p>La fonction contenant le mot-clé <code>yield</code> est un générateur. Lorsqu'on l'appelle, ses paramètres formels sont liés aux arguments effectifs, mais son corps n'est pas évalué. Au lieu de cela, un générateur-itérateur est renvoyé. Chaque appel à la méthode <code>next()</code> du générateur-itérateur provoque un nouveau passage au travers de l'algorithme itératif. La valeur à chaque étape est celle spécifiée par le mot-clé <code>yield</code>. Pensez à <code>yield</code> comme la version générateur-itérateur de <code>return</code>, indiquant la limite entre chaque itération de l'algorithme. Chaque fois que <code>next()</code> est appelée, le code du générateur reprend à l'instruction suivant le <code>yield</code>.
</p><p>On cycle dans un générateur-itérateur en appelant à plusieurs reprises sa méthode <code>next()</code> jusqu'à ce que la condition résultante désirée soit atteinte. Dans cet exemple, on peut obtenir autant de nombres de Fibonacci que l'on veut en continuant à appeler <code>g.next()</code> jusqu'à ce que le nombre de résultats voulu soit atteint.
</p>
<h4 name="It.C3.A9rateurs"> Itérateurs </h4>
<p>Un <i>itérateur</i> est un objet spécial qui permet un parcours itératif de données.
</p><p>Dans leur utilisation normale, les objets itérateurs sont « invisibles » ; il n'est pas nécessaire de les utiliser explicitement, mais on utilisera plutôt les instructions JavaScript <a href="fr/Guide_JavaScript_1.5/Instructions_de_manipulation_d'objets"><code>for...in</code> et <code>for each...in</code></a> pour boucler de manière naturelle sur les clés et/ou valeurs des objets.
</p>
<pre>var objectWithIterator = getObjectSomehow();

for (var i in objectWithIterator)
{
  document.write(objectWithIterator[i] + "&lt;BR&gt;\n");
}
</pre>
<p>Si vous implémentez votre propre objet itérateur, ou avez besoin pour une autre raison de manipuler des itérateurs, vous devrez connaître la méthode <code>next</code>, l'exception <code>StopIteration</code> et la propriété <code>__iterator__</code>.
</p><p>On peut créer un itérateur pour un objet en appelant <code>Iterator(<i>nomdobjet</i>)</code> ; l'itérateur d'un objet peut être trouvé en utilisant sa propriété <code>__iterator__</code>, qui par défaut implémente l'itération selon le modèle habituel <code>for...in</code> et <code>for each...in</code>. Si vous voulez fournir un itérateur personnalisé, vous devez écraser <a href="fr/Guide_JavaScript_1.5/Cr%c3%a9ation_d'objets/D%c3%a9finition_d'accesseurs_et_de_mutateurs">l'accesseur</a> pour <code>__iterator__</code> afin qu'il renvoie une instance de votre itérateur personnalisé. Pour obtenir un itérateur d'objet depuis un script, vous devriez utiliser  <code>Iterator(<i>obj</i>)</code> plutôt qu'accéder à la propriété <code>__iterator__</code> directement.
</p><p>Une fois l'itérateur obtenu, il est facile de passer à l'élément suivant dans l'objet en appelant la méthode <code>next()</code> de l'itérateur. S'il n'y a plus de donnée à parcourir, l'exception <code>StopIteration</code> est déclenchée.
</p><p>Voici un exemple simple de manipulation directe d'un itérateur :
</p>
<pre>var obj = {name:"Jack Bauer", username:"JackB", id:12345, agency:"CTU", region:"Los Angeles"};

var it = Iterator(obj);

try {
  while (true) {
    document.write(it.next() + "&lt;BR&gt;\n");
  }
} catch (err if err instanceof StopIteration) {
  document.write("End of record.&lt;BR&gt;\n");
} catch (err) {
  document.write("Unknown error: " + err.description + "&lt;BR&gt;\n");
}
</pre>
<p>Le résultat affiché par ce programme ressemble à ceci :
</p>
<pre>name,Jack Bauer
username,JackB
id,12345
agency,CTU
region,Los Angeles
End of record.
</pre>
<p>Il est possible, optionnellement, de spécifier un second paramètre à la création de l'itérateur, qui est une valeur booléenne indiquant si seules les clés doivent être renvoyées à chaque fois que la méthode <code>next()</code> est appelée. Si on change <code>var it = Iterator(obj);</code> en <code>var it = Iterator(obj, true);</code> dans l'exemple ci-dessus, on obtient le résultat suivant :
</p>
<pre>name
username
id
agency
region
End of record.
</pre>
<p>Dans les deux cas, l'ordre réel dans lequel les données sont renvoyées peut varier selon l'implémentation. Aucun ordre n'est garanti dans les données.
</p><p>Les itérateurs sont une manière pratique de parcourir les données dans des objets, même les objets qui peuvent contenir des données dont vous ne connaissez pas l'existence. C'est particulièrement utile dans le cas où des données non attendues par votre application doivent toutefois être préservées.
</p>
<h3 name="D.C3.A9finition_de_tableaux_par_compr.C3.A9hension"> Définition de tableaux par compréhension </h3>
<p>Les tableaux définis par compréhension sont une utilisation des générateurs fournissant une manière pratique et puissante d'initialiser des tableaux. Par exemple :
</p>
<pre class="eval">function range(begin, end) {
  for (let i = begin; i &lt; end; ++i) {
    yield i;
  }
}
</pre>
<p><code>range()</code> est un générateur renvoyant toutes les valeurs entre <tt>begin</tt> et <tt>end</tt>. Une fois cette fonction définie, on peut l'utiliser comme ceci :
</p>
<pre class="eval">var ten_squares = [i * i for (i in range(0, 10))];
</pre>
<p>Un nouveau tableau <var>ten_squares</var> est préinitialisé pour contenir les carrés des valeurs dans l'intervalle <code>0..9</code>.
</p><p>On peut préciser n'importe quelle condition à l'initialisation du tableau. Si vous voulez initialiser un tableau pour contenir les nombres pairs entre 0 et 20, vous pouvez utiliser ce code :
</p>
<pre class="eval">var evens = [i for (i in range(0, 21)) if (i % 2 == 0)];
</pre>
<p>Avant JavaScript 1.7, il aurait été nécessaire d'écrire quelque chose de semblable à ceci :
</p>
<pre>var evens = [];
for (var i=0; i &lt;= 20; i++) {
  if (i % 2 == 0)
    evens.push(i);
}
</pre>
<p>La notation par compréhension est non seulement plus compacte, mais elle est également plus facile à lire une fois familiarisé avec le concept.
</p>
<h4 name="R.C3.A8gles_de_port.C3.A9e"> Règles de portée </h4>
<p>Les définitions de tableaux par compréhension ont un bloc implicite autour d'elles, contenant tout ce qui se trouve entre les crochets droits, ainsi que des déclarations <code>let</code> implicites.
</p><p><i>Plus de détails sont nécessaires.</i>
</p>
<h3 name="Port.C3.A9e_des_variables_avec_let"> Portée des variables avec <code>let</code> </h3>
<p>Il y a plusieurs manières d'utiliser <code>let</code> pour gérer la porté de bloc de données et de fonctions :
</p>
<ul><li> L'<b>instruction <code>let</code></b> est une manière d'associer des valeurs avec des variables, constantes et fonctions au sein d'un bloc sans affecter les valeurs de variables portant le même nom en dehors du bloc.
</li><li> L'<b>expression <code>let</code></b> permet de mettre en place des variables dont la portée se limite à une seule expression.
</li><li> La <b>définition avec <code>let</code></b> définit des variables, constantes et fonctions dont la portée est limitée au bloc dans lequel elles sont définies. Cette syntaxe est très similaire à celle utilisée avec <code>var</code>.
</li><li> Il est également possible d'utiliser <code>let</code> pour mettre en place des variables existant uniquement dans le contexte d'une boucle <code>for</code>.
</li></ul>
<h4 name="L.27instruction_let"> L'instruction <code>let</code> </h4>
<p>L'instruction <code>let</code> fournit une portée locale pour les variables, constantes et fonctions. Elle fonctionne en liant un ensemble de variables à la portée lexicale d'un seul bloc de code. La valeur de terminaison de l'instruction <code>let</code> est celle du bloc.
</p><p>Par exemple :
</p>
<pre>var x = 5;
var y = 0;

let (x = x+10, y = 12) {
  document.write(x+y + "&lt;BR&gt;\n");
}

document.write(x+y + "&lt;BR&gt;\n");
</pre>
<p>L'affichage produit par ce programme sera :
</p>
<pre>27
5
</pre>
<p>Les règles pour le bloc de code sont les mêmes que pour n'importe quel autre bloc de code en JavaScript. Il peut avoir ses propres variables locales déclarées à l'aide de  <code>let</code>.
</p>
<div class="note"><b>Note :</b> Les parenthèses suivant <code>let</code> sont ici obligatoires. Leur absence résulterait en une erreur de syntaxe.</div>
<h5 name="R.C3.A8gles_de_port.C3.A9e_2"> Règles de portée </h5>
<p>La portée des variables définies à l'aide de <code>let</code> est le bloc <code>let</code> lui-même, ainsi que tout bloc interne contenu à l'intérieur de celui-ci, à moins que ces blocs définissent des variables ayant les mêmes noms.
</p>
<h4 name="Expressions_avec_let"> Expressions avec <code>let</code> </h4>
<p>On peut utiliser <code>let</code> pour définir des variables dont la portée se limitent à une seule expression :
</p>
<pre class="eval">var x = 5;
var y = 0;
document.write( let(x = x + 10, y = 12) x+y  + "<br>\n");
document.write(x+y + "<br>\n");
</pre>
<p>L'affichage produit est :
</p>
<pre class="eval">27
5
</pre>
<p>Dans ce cas, la liaison entre les valeurs de <var>x</var> et <var>y</var>, et les expressions <code>x+10</code> et <code>12</code> a une portée limitée uniquement à l'expression <code>x+y</code>.
</p>
<h5 name="R.C3.A8gles_de_port.C3.A9e_3"> Règles de portée </h5>
<p>Avec une expression <code>let</code> donnée :
</p>
<pre class="eval">let (<var>decls</var>) <var style="color: blue">expr</var>
</pre>
<p>Un bloc implicite est créé autour de <var style="color: blue">expr</var>.
</p>
<h4 name="D.C3.A9finitions_avec_let"> Définitions avec <code>let</code> </h4>
<p>Le mot-clé <code>let</code> peut également être utilisé pour définir des variables, constantes et fonctions au sein d'un bloc.
</p>
<pre> ** Ce code dne fonctionne pas dans Firefox 2.0 b1. **
if (x &gt; y)
{
   let const k = 37;
   let gamma : int = 12.7 + k;
   let i = 10;
   let function f(n) { return (n/3)+k; }
   return f(gamma) + f(i);
}
</pre>
<h5 name="R.C3.A8gles_de_port.C3.A9e_4"> Règles de portée </h5>
<p>Les variables, fonctions et constantes déclarées avec <code>let</code>, <code>let function</code> et <code>let const</code> ont leur portée limitée au bloc dans lequel elles sont définies, ainsi que dans tout sous-bloc dans lequel elles ne sont pas redéfinies. Dans ce sens, <code>let</code> fonctionne tout à fait comme <code>var</code>.
</p><p>Dans les programmes et classes, <code>let</code> ne crée pas de propriétés sur les objets global et de classe comme le ferait <code>var</code> ; au lieu de cela, des propriétés sont créées dans un bloc implicite créé pour l'évaluation des instructions dans ces contextes. Essentiellement, cela signifie que <code>let</code> n'écrasera pas de variables définies précédemment avec <code>var</code>. Par exemple :
</p>
<pre class="eval">** Ne fonctionne pas dans Firefox 2.0 b1. Renvoie "42" au lieu de "global".
var x = 'global';
let x = 42;
document.write(this.x + "<br>\n");
</pre>
<p>Ce code affichera « global », et non « 42 ».
</p><p>Un <i>bloc implicite</i> est un bloc non entouré de crochets ; il est créé implicitement par le moteur JavaScript.
</p><p>Dans les fonctions, <code>let</code> lorsqu'il est exécuté par <code>eval()</code> ne crée pas de propriétés sur l'objet de la variable (objet d'activation ou de liaison interne) comme <code>var</code> le ferait ; au lieu de cela, des propriétés sont créées dans un bloc implicite créé pour l'évaluation d'instuctions dans le programme. Il s'agit d'une conséquence du comportement d'<code>eval()</code> sur des programmes combiné avec la règle qui précède.
</p><p>Autrement dit, lorsqu'<code>eval()</code> est utilisé pour exécuter du code, ce code est traité comme un programme indépendant, qui a son propre bloc implicite autour de son code.
</p>
<h4 name="Variables_d.C3.A9clar.C3.A9es_avec_let_dans_des_boucles_for"> Variables déclarées avec <code>let</code> dans des boucles <code>for</code> </h4>
<p>Le mot-clé <code>let</code> peut être utilisé pour lier des variables localement dans la portée de boucles <code>for</code>, exactement comme avec <code>var</code>.
</p>
<pre>   var i=0;
   for ( let i=i ; i &lt; 10 ; i++ )
     document.write(i + "&lt;BR&gt;\n");

   for ( let &amp;[name,value] in obj )
     document.write("Name: " + name + ", Value: " + value + "&lt;BR&gt;\n");
</pre>
<h5 name="R.C3.A8gles_de_port.C3.A9e_5"> Règles de portée </h5>
<pre class="eval">for (let <var>expr1</var>; <var style="color: blue">expr2</var>; <var style="color: blue">expr3</var>) <var style="color: blue">statement</var>
</pre>
<p>Dans cet exemple, <var style="color: blue">expr2</var>, <var style="color: blue">expr3</var> et <var style="color: blue">statement</var> font partie d'un bloc implicite contenant les variables de bloc déclarées avec <code>let <var>expr1</var></code>. C'est ce qui est montré dans la première boucle ci-dessus.
</p>
<pre class="eval">for (<var>expr1</var> in <var>expr2</var>) <var style="color: blue">statement</var>
</pre>
<p>Dans ce cas, un bloc implicite contient <var style="color: blue">statement</var>. C'est ce qui est montré dans la seconde boucle ci-dessus.
</p>
<h3 name="Assignation_d.C3.A9structurante"> Assignation déstructurante </h3>
<p>L'assignation déstructurente rend possible l'extraction de données depuis des tableaux ou des objets en utilisant une syntaxe reproduisant celle des déclarations littérales de tableaux et d'objets.
</p><p>Les expressions littérales d'objet et de tableau forment une manière facile de créer des paquets de données ad-hoc. Une fois ces paquets créés, ils peuvent être utilisés de n'importe quelle manière. Ils peuvent même être renvoyés par des fonctions.
</p><p>Une application particulièrement utile de l'assignation déstructurée est de lire une structure entière en une seule instruction, bien qu'il y ait un bon nombre d'autre choses intéressantes comme le montrent les exemples développés plus bas.
</p><p>Cette possibilité est similaire à celles qui sont présentes dans des langages comme Perl et Python.
</p>
<h4 name="Exemples"> Exemples </h4>
<p>L'assignation déstructurée s'explique le mieux au travers d'exemples, en voici donc quelques uns qui vous permettront de comprendre.
</p>
<div class="note"><b>Note :</b> si vous avez des exemples intéressants d'utilisation de l'assignation déstructurée, n'hésitez pas à les ajouter à cette section.</div>
<h5 name=".C3.89change_de_valeurs"> Échange de valeurs </h5>
<p>L'assignation déstructurée peut par exemple être utilisée pour échanger des valeurs :
</p>
<pre class="eval">var a = 1;
var b = 3;
[a, b] = [b, a];
</pre>
<p>Après exécution de ce code, <var>b</var> vaut 1 et <var>a</var> vaut 3.
</p>
<h5 name="Renvoi_de_valeurs_multiples"> Renvoi de valeurs multiples </h5>
<p>Grâce à l'assignation déstructurante, les fonctions peuvent renvoyer plusieurs valeurs. Bien qu'il ait toujours été possible de renvoyer un tableau, on a ici un degré de flexibilité supplémentaire :
</p><p><br>
</p>
<pre class="eval">function f() {
  return [1, 2];
}
</pre>
<p>Comme vous pouvez le voir, le renvoi de résultats se fait à l'aide d'une notation semblable à un tableau, avec toutes les valeurs à renvoyer entourées de crochets droits. N'importe quel nombre de résultats peut être renvoyé de cette manière. Dans cet exemple, <code>f()</code> renvoie les valeurs <code>{{mediawiki.external('1, 2')}}</code>.
</p>
<pre class="eval">var a, b;
[a, b] = f();
document.write ("A vaut " + a + " B vaut " + b + "<br>\n");
</pre>
<p>La commande <code>{{mediawiki.external('a, b')}} = f()</code> assigne le résultat de la fonction aux variables entre crochets, dans l'ordre : <var>a</var> est positionnée à 1 et <var>b</var> est positionnée à 2.
</p><p>Les valeurs de retour peuvent également être récupérées dans un tableau :
</p>
<pre class="eval">var a = f();
document.write ("A is " + a);
</pre>
<p>Dans ce cas, <var>a</var> est un tableau contenant les valeurs 1 et 2.
</p>
<h5 name="Ignorer_certaines_valeurs_renvoy.C3.A9es"> Ignorer certaines valeurs renvoyées </h5>
<p>Il est également possible d'ignorer les valeurs de retour qui ne vous intéressent pas :
</p>
<pre>function f() {
  return [1, 2, 3];
}

var [a,, b] = f();
document.write ("A is " + a + " B is " + b + "&lt;BR&gt;\n");
</pre>
<p>Après exécution de ce code, <var>a</var> vaut 1 et <var>b</var> vaut 3. La valeur 2 est ignorée. Il est possible d'ignorer toute (ou toutes les) valeur(s) renvoyée(s) de cette manière. Par exemple :
</p>
<pre class="eval">[,,,] = f();
</pre>
<h5 name="Parcours_d.27objets"> Parcours d'objets </h5>
<p>L'assignation déstructurante peut également être utilisée pour extraire des données d'un objet :
</p>
<pre>for (let[name, value] in obj) {
  print("Name: " + name + ", Value: " + value);
}
</pre>
<p>Ceci récupère les champs <var>name</var> et <var>value</var> d'un objet <var>obj</var> et les affiche.
</p>
<h4 name="Parcours_des_valeurs_d.27un_objet"> Parcours des valeurs d'un objet </h4>
<p>Il est possible de parcourir les valeur d'un objet de la même manière :
</p>
<pre>for each (let {name: n, family: { father: f } } in obj) {
  print("Name: " + n + ", Father: " + f);
}
</pre>
<p><i>Manque une explication sur ce que cela fait</i>
</p>
<h3 name="Capture_de_lignes_et_mise_.C3.A0_jour_d.27enregistrements"> Capture de lignes et mise à jour d'enregistrements </h3>
<p>Liée à l'assignation déstructurante, la capture de lignes permet de récupérer des champs individuels d'une structure, ainsi qu'une nouvelle structure contenant les champs que vous n'avez pas explicitement extraits.
</p><p>Par exemple :
</p>
<pre>var personRecord = { name: "Bob", city: "Foohaven", job: "Programmer", employer: "Barco Inc." };

{ name: x, city: y, ...: z } = personRecord;
</pre>
<p>Ce code extrait les champs <var>name</var> et <var>city</var> dans les variables <var>x</var> et <var>y</var>, respectivement, et crée également une nouvelle structure, <var>z</var>, qui contient <code>{ job: "Programmer", employer: "Barco Inc." }</code>.
</p><p>Une utilisation pratique de cette possibilité est la préservation de données. Si votre code doit être capable de travailler sur des données pouvant contenir des champs dont vous n'avez pas connaissance, vous pouvez extraire les champs inconnus dans une structure pour les préserver même si vous ne connaissez pas leurs noms.
</p><p>Les valeurs et structures peuvent également être combinées ensemble à l'aide de cette syntaxe. Par exemple, si Bob déménage, il faut changer le champ <var>city</var> dans l'enregistrement ci-dessus. Après cela, l'enregistrement complet peut être reconstruit avec les nouvelles données.
</p><p>Cela peut se faire très facilement, comme ceci :
</p>
<pre class="eval">var newPersonRecord = { ... = z, city = "New Foohaven" };
</pre>
<p>Après cela, <var>newPersonRecord</var> contient <code>{ name: "Bob", city: "New Foohaven", job: "Programmer", employer: "Barco Inc." }</code>.
</p><p>En termes simples, « <code>...</code> » est un raccourci pour « tout champ que je n'ai pas explicitement mentionné. »
</p>{{ wiki.languages( { "en": "en/New_in_JavaScript_1.7", "pl": "pl/Nowo\u015bci_w_JavaScript_1.7" } ) }}
Revenir à cette révision