samedi, 23 mai 2015

ES6 en détails : les itérateurs et la boucle for-of

Suite de la traduction, qui continue la série d’articles de Jason Orendorff. L’article original se trouve ici.

Merci aux traducteurs et relecteurs :) Marine, Mentalo, Benjamin, Amarok, Lucas, Ilphrin et Goofy !


ES6 en détails est une série d’articles décrivant les nouvelles fonctionnalités ajoutées au langage de programmation JavaScript avec la sixième édition du standard ECMAScript (ES6 en abrégé).

Comment itérer sur les éléments d’un tableau ? Lorsque JavaScript est apparu, il y a vingt ans de ça, on aurait fait ainsi :

for (var index = 0; index < monTableau.length; index++) {
  console.log(monTableau[index]);
}

Depuis ES5, on peut utiliser la méthode native forEach :

monTableau.forEach(function (value) {
  console.log(value);
});

C’est un petit peu plus court, mais il y a un léger inconvénient : il n’est pas possible de sortir de cette boucle avec une instruction break ou de faire retourner la fonction englobante avec une instruction return.

Ce serait effectivement agréable s’il y avait une syntaxe de boucle for itérant directement sur les éléments du tableau.

Quid d’une boucle for-in ?

for (var index in monTableau) {    
  // ne faites pas ceci
  console.log(monTableau[index]);
}

C’est une mauvaise idée pour plusieurs raisons :

  1. Les valeurs assignées pour l’index dans ce code sont les chaînes de caractères "0", "1", "2", et ainsi de suite : ce ne sont pas réellement des nombres. Étant donné qu’on ne souhaite sûrement pas manipuler des chaînes de façon arithmétique ("2" + 1 == "21"), c’est, a minima, peu pratique ;
  2. Le corps de la boucle ne va pas seulement s’exécuter pour chaque élément du tableau, mais également pour toutes les propriétés non-natives que l’on pourrait avoir ajoutées. Par exemple, si votre tableau possède une propriété énumérable monTableau.nom, alors cette boucle va s’exécuter une fois de plus, avec index == "nom". Même les propriétés présentes sur la chaîne de prototypes du tableau peuvent être visitées ;
  3. Le plus étonnant dans tout ça est que, dans certaines circonstances, ce code va boucler sur les éléments du tableau dans un ordre arbitraire.

Pour faire court, for-in a été pensé pour travailler avec de bons vieux objets (type Object) dont les clés sont des chaînes de caractères. Pour les tableaux (type Array), ce n’est pas génial.

La puissante boucle for-of

Vous souvenez-vous de la semaine dernière, lorsque j’ai promis qu’ES6 ne casserait pas le code JavaScript que vous avez déjà écrit ? En fait, il existe des millions de sites Web qui dépendent du comportement de for-in — oui, même de son comportement sur les tableaux. Il n’a donc jamais été question de « réparer » for-in afin qu’elle soit plus utile pour manipuler avec des tableaux. Le seul moyen pour ES6 d’améliorer les choses était d’ajouter une nouvelle forme de syntaxe de boucle.

La voilà :

for (var valeur of monTableau) {
  console.log(valeur);
}

Hmm. Après toute cette publicité, ça ne semble pas si impressionnant, n’est-ce pas ? Pourtant, nous allons voir que for-of a plus d’un tour dans son sac. Pour l’instant, notez simplement que :

  1. C’est la syntaxe la plus concise et la plus directe pour boucler sur les éléments d’un tableau ;
  2. Celle-ci permet d’éviter les pièges de for-in ;
  3. Contrairement à forEach(), elle est compatible avec les instructions break, continue et return.

La boucle for-in est faite pour boucler sur les propriétés d’un objet.

La boucle for-of est faite pour boucler sur des données — comme les valeurs d’un tableau.

Mais ce n’est pas tout.

for-of fonctionne également avec les autres collections

for-of n’est pas restreint aux tableaux. Cela fonctionne également avec la plupart des objets qui agissent comme des tableaux, telles que les NodeList du DOM. Cela fonctionne également sur les chaînes de caractères, en considérant que la chaîne est une séquence de caractères Unicode :

for (var chr of "♂ ♀"){
  alert(chr);
}

Cela fonctionne également avec les objets Map et Set.

Oh, désolé si vous n’avez jamais entendu parler des objets Map et Set, ceux-ci sont des nouveautés apportées par ES6. Nous en parlerons plus tard dans un article dédié. Si vous avez déjà utilisé des Maps (dictionnaires) et Sets (ensembles) dans d’autres langages, vous ne serez pas très surpris.

Par exemple, un objet Set peut être utilisé pour éliminer des doublons :

// créons un ensemble à partir d'un tableau de mots
var motsUniques = new Set(mots);

Une fois que l’on a un ensemble (Set), que se passe-t-il si on veut itérer sur son contenu ? Facile :

for (var mot of motsUniques) {
  console.log(mot);
}

Une Map est légèrement différente : les données que celle-ci contient sont des paires de clés-valeurs, il faudra donc utiliser l’affectation « destructurée » (destructuring) pour séparer la clé et la valeur en deux variables distinctes :

for (var [clé, valeur] of annuaireMap) {
  console.log("Le numéro de téléphone de "+clé +" est " + valeur);
}

La décomposition est une autre fonctionnalité, également apparue avec ES6 qui fera un sujet idéal pour un prochain article que j’écrirai.

Maintenant, vous avez une idée du tableau : JS possède déjà un certain nombre de structures de données pour des collections, et il y en a encore plus à venir. for-of a été pensé pour être l’instruction de boucle ultime à utiliser avec toutes ces structures.

for-of ne fonctionne pas avec des objets tout simples, mais si vous voulez itérer sur les propriétés d’un objet, vous pouvez soit utiliser for-in (c’est sa raison d’être), soit la fonction native Object.keys() :

// affiche toutes les propriétés propres énumérables 
// d'un objet dans la console
for (var clé of Object.keys(monObjet)) {
  console.log(clé + ": " + monObjet[clé]);
}

Sous le capot

« Les bons artistes copient, les très bons artistes volent » — Pablo Picasso

Un thème récurrent d’ES6 est le fait que les nouvelles fonctionnalités ajoutées au langage ne viennent pas de nulle part. La plupart ont été essayées et se sont avérées utiles dans d’autres langages.

La boucle for-of, par exemple, rappelle des instructions de boucle similaires en C++, Java, C#, et Python. Comme celles-ci, elle fonctionne avec des structures de données différentes, fournies par le langage et sa bibliothèque standard. Mais c’est également un ajout au langage.

De même qu’avec les instructions for ou forEach dans ces autres langages, for-of fonctionne entièrement à l’aide d’appels de fonctions. Ce que les tableaux (objets Array), dictionnaires (objets Map), ensembles (objets Set) et les autres objets ont en commun est le fait qu’ils ont chacun une méthode iterator (NdT : pour « itérateur »).

Il existe une autre catégorie d’objets qui peuvent aussi avoir une méthode iterator : n’importe quel objet.

De la même manière que lorsqu’on ajoute une méthode monObjet.toString() à n’importe quel objet, JS sait comment convertir cet objet en une chaîne de caractères, on peut ajouter la méthode monObjetSymbol.iterator() à n’importe quel objet, et, soudainement, JS sait comment itérer sur cet objet.

Par exemple, imaginons que vous utilisiez jQuery, et que, bien que vous soyez très fan de .each(), vous aimeriez que les objets jQuery fonctionnent également avec for-of. Voici la manière de procéder :

// Comme les objets jQuery se comportent comme des tableaux,
// donnons-leur la même méthode iterator que celle de l'objet Array
jQuery.prototype[Symbol.iterator] =
Array.prototype[Symbol.iterator];

OK, je sais ce que vous êtes en train de vous dire. Cette syntaxe Symbol.iterator est bizarre. Que se passe-t-il ici ? C’est en lien avec le nom de la méthode. Le comité de standardisation aurait pu appeler cette méthode .iterator(), or dans ce cas, votre code aurait déjà pu comporter des objets ayant une méthode .iterator(), et cela aurait pu être une source de confusion. C’est pourquoi le standard préfère utiliser un symbole plutôt qu’une chaine de caractères comme nom de la méthode.

Les symboles sont apparus avec ES6, et nous vous expliquerons tout sur eux — vous l’avez deviné — dans un prochain article de blog. Pour l’instant, tout ce que vous avez besoin de savoir, c’est que le standard peut définir un symbole entièrement nouveau, comme Symbol.iterator, et qu’il est garanti que cela ne créera pas de conflit avec du code existant. Le compromis que cela implique est une syntaxe un peu étrange. Mais c’est un petit prix à payer pour cette nouvelle fonctionnalité versatile et la garantie d’une excellente rétro-compatibilité.

Un objet qui possède une méthode Symbol.iterator() est appelé un itérable. Dans les semaines qui viennent, nous verrons que le concept d’objets itérables est utilisé à travers tout le langage, pas seulement avec for-of mais également avec les constructeurs des objets Map et Set, avec les affectations déstructurées et avec le nouvel opérateur « spread » (NdT : ou « opérateur de décomposition »).

Les objets itérateurs

Il est probable que vous n’ayez jamais à implémenter un itérateur de A à Z. On verra pourquoi la semaine prochaine. Cependant, pour être tout à fait complet, regardons de près à quoi ressemble un objet itérable (si vous sautez cette section, vous ne manquerez que quelques détails techniques).

Une boucle for-of commence par appeler la méthode Symbol.iterator() de la collection utilisée. Ceci renvoie un nouvel itérateur qui peut être n’importe quel objet possédant une méthode .next() ; la boucle for-of appellera cette méthode de façon répétitive, une fois pour chaque itération. Par exemple, voici l’itérateur le plus simple auquel je peux penser :

var itérateurPleinDeZéros = {
   [Symbol.iterator]: function () {
    return this;
  },
  next: function () {
    return {done: false, value: 0};
  }
};

À chaque appel de la méthode .next(), le même résultat sera renvoyé et communiquera les informations suivantes à la boucle for-of :

  1. nous n’avons pas encore terminé les itérations ;
  2. la prochaine valeur est 0.

Cela signifie que la boucle for (valeur of itérateurPleinDeZéros) {} sera une boucle infinie. Évidemment, un itérateur utilisé dans du code ne sera pas aussi trivial.

Ce concept d’itérateur, avec les propriétés .done et .value, est légèrement différente de celui utilisé dans les autres langages. En Java, les itérateurs possèdent des méthodes séparées .hasNext() et .next(). En Python, ils possèdent une seule méthode .next() qui appelle StopIteration lorsqu’il n’y a plus de valeur. Fondamentalement, ces trois conceptions renvoient les mêmes informations.

Un itérateur peut également implémenter les méthodes optionnelles .return() et .throw(exc). La boucle for-of appelle la méthode .return() si la boucle est interrompue de façon prématurée, à cause d’une exception, d’une instruction break ou return.

Un itérateur peut également implémenter la méthode return() s’il est nécessaire de procéder à un nettoyage ou de libérer des ressources utilisées. La plupart des objets itérateurs n’auront pas à implémenter cette méthode. La méthode throw(exc) est un cas encore plus spécifique : les boucles for-of ne les appellent jamais, on en parlera la semaine prochaine.

Maintenant que nous connaissons tous les détails, nous pouvons nous intéresser à une boucle for-of simple et la ré-écrire avec les appels des méthodes sous-jacentes.

Commençons avec la boucle for-of :

for (VAR of ITERABLE) {
  INSTRUCTIONS
}

Voici un équivalent, un peu brut, utilisant les méthodes sous-jacentes ainsi que quelques variables temporaires :

var $iterator = ITERABLE[Symbol.iterator]();
var $result = $iterator.next();
while (!result.done) {
  VAR = result.value;
  INSTRUCTIONS
  $result = $iterator.next();
}

Ce code n’illustre pas l’utilisation de la méthode .return(). On pourrait l’ajouter mais je pense que cela ajouterait plus de confusion. Les boucles for-of sont simples à utiliser, malgré cela, il se passe beaucoup de choses en arrière-plan.

Quand puis-je commencer à utiliser cette fonctionnalité ?

Les boucles for-of sont supportées par les versions actuelles de Firefox. Elles sont supportés dans Chrome sous réserve d’activer l’option « Activer la fonctionnalité expérimentale JavaScript » accessible via l’URL chrome://flags. Cela fonctionne également dans le prochain navigateur Edge (nom de code « Spartan ») de Microsoft. En revanche, cette fonctionnalité n’est pas disponible dans les différentes versions d’Internet Explorer. Si vous souhaitez utiliser cette nouvelle syntaxe et que devez prendre en compte IE et Safari, vous pouvez utiliser un compilateur tel que Babel ou Traceur de Google pour traduire votre code ES6 en code ES5, plus largement compatible avec les anciens navigateurs.

Côté serveur, pas besoin d’installer un compilateur - vous pouvez utiliser les boucles for-of dès aujourd’hui avec io.js (et avec Node en utilisant l’option --harmony)

(Mise à jour : j’ai oublié de mentionner que for-of est désactivé par défaut dans Chrome. Merci à Oleg d’avoir signalé cet oubli dans les les commentaires.) (NdT : voir ce commentaire).

{done: true}

Whaou !

Bon, c’est tout pour aujourd’hui, mais nous n’en n’avons toujours pas fini avec la boucle for-of.

Il y a encore une nouvelle sorte d’objet apparue avec ES6 et qui fonctionne très bien avec les boucles for-of. Je n’en ai pas parlé car c’est le sujet de l’article de la semaine prochaine. Je pense que cette nouvelle fonctionnalité est la plus magique d’ES6. Si vous ne l’avez jamais utilisé dans des langages comme Python et C#, vous serez vraisemblablement déstabilisé au début. Ce sera la manière la plus simple d’écrire un itérateur, un atout pour le refactoring et cela pourrait changer la façon d’écrire du code asynchrone tant au niveau du navigateur que du serveur.

Rejoignez-nous donc la semaine prochaine pour une étude approfondie des générateurs dans ES6.

mardi, 19 mai 2015

ES6 en détails : une introduction

Ce billet est une traduction de cet article, écrit par Jason Orendorff qui participe au développement du moteur JavaScript de Firefox. Ce billet sera le premier d’une série de traductions, chaque billet décrivant une nouvelle fonctionnalité apportée par ECMAScript 6.

Merci à Marine, Mentalo, Lucas et Benjamin pour la traduction :)


Lire la suite

mardi, 23 avril 2013

Première contribution : rapporter un bogue sur Bugzilla

image 1 formulaire grand format

Il est notoire que le bugzilla de Mozilla peut s’avérer difficile à aborder et maîtriser. Pour vous guider dans ce labyrinthe, Liz Henry a rédigé un très bon article illustré sur son blog :  File a bug: the missing manual, now with unicorns. Nous vous le proposons ici en espérant qu’il vous incitera  […]

Lire la suite

jeudi, 14 mars 2013

Firefox OS et l’évolution des API Web - par Brendan Eich

Dans cet article que MozFr a traduit pour vous ci-dessous, Brendan Eich qui est le créateur du JavaScript et l’un des fondateurs de Mozilla fait le point sur le succès qui accompagne le lancement de Firefox OS et sur l’intérêt des nombreuses API pour mobiles que Mozilla propose à la standardisation,  […]

Lire la suite

Optimiser les accès de variables JavaScript

Cet article est issu du blog de Luke Wagner. L’article original a été écrit en anglais par Luke Wagner. J’ai récemment fini un projet visant à améliorer la manière dont SpiderMonkey implémente les accès de variable, ainsi j’ai pensé qu’il était temps d’expliquer comment cela fonctionne désormais. En  […]

Lire la suite

mardi, 19 février 2013

L'assembleur du Web

Re-publication du billet de CLOCHIX sur son blog asm.js est un projet de recherche de Mozilla qui vise à améliorer les performances de JavaScript en n’utilisant qu’un sous-ensemble du langage, plus facile à optimiser. Il se compose de plusieurs sous-projets : la spécification du langage ;  […]

Lire la suite

lundi, 15 octobre 2012

IonMonkey arrive dans Firefox 18

Kraken

Cet article est issu du blog JavaScript de Mozilla. L’article original a été écrit en anglais par David Anderson. Depuis le lundi 12 septembre, IonMonkey, notre nouveau compilateur JavaScript à la volée, est arrivé dans Firefox 18. IonMonkey représente un grand pas en avant pour nos performances sur  […]

Lire la suite

jeudi, 4 octobre 2012

Ramasse-miettes incrémentiel dans Firefox 16

nonincremental.png

Cet article est issu du blog JavaScript de Mozilla. L’article original a été écrit en anglais par Bill McCloskey. Firefox 16 va être la première version à supporter un ramasse-miettes (en anglais Garbage Collector ou GC) incrémentiel. C’est une fonctionnalité majeure, ayant nécessité plus d’un an de  […]

Lire la suite

mercredi, 3 octobre 2012

Présentation du nouveau blog officiel de l'équipe JavaScript de Mozilla

La mission de Mozilla est de «  promouvoir l’ouverture, l’innovation et les possibilités offertes sur la toile  ». Les membres de l’équipe du moteur JavaScript ont une occasion unique de soutenir cette mission. Leur travail passe par des défis techniques tels que la création d’un ramasse-miettes  […]

Lire la suite

vendredi, 27 juillet 2012

about:csswg - Sources d'innovation

Cet article est issue d’une série d’article sur le fonctionnement du CSS Working Group au W3C. L’article original a été écris en anglais par Fantasai. Sources d’innovation Il y a eu de nombreux débats pour savoir si les standards devaient découler des implémentations ou si ce sont les  […]

Lire la suite

mardi, 24 juillet 2012

about:csswg - Processus de spécification


Lire la suite

samedi, 21 juillet 2012

about:csswg - Modularité

Cet article est issue d’une série d’article sur le fonctionnement du CSS Working Group au W3C. L’article original a été écris en anglais par Fantasai. Modularité de CSS Lorsque CSS Level 3 a été créé, il a été pensé comme un ensemble de spécifications modulaires permettant de recréer CSS Level 2 et  […]

Lire la suite

vendredi, 20 juillet 2012

about:csswg - Prise de décisions

Cet article est issue d’une série d’article sur le fonctionnement du CSS Working Group au W3C. L’article original a été écris en anglais par Fantasai. Prise de décisions Comme défini dans le processus du W3C, le CSS WG prend des décisions par consensus. Le consensus dans le CSS WG est généralement  […]

Lire la suite

mercredi, 18 juillet 2012

about:csswg - Communication

Cet article est issue d’une série d’article sur le fonctionnement du CSS Working Group au W3C. L’article original a été écris en anglais par Fantasai. Communication Le CSS Working Group communique régulièrement à trois niveaux différents : Liste de diffusion Les discussions techniques sur les  […]

Lire la suite

vendredi, 13 juillet 2012

about:csswg - Personnes et responsabilités


Lire la suite

samedi, 7 juillet 2012

about:csswg

Nous avons traduit pour vous une série d’articles écrits par Fantasai sur le fonctionnement du CSS Working Group, Fantasai est une employée Mozilla qui participe à l’élaboration du standard CSS depuis plus d’une dizaine d’années maintenant. On ne la remerciera jamais assez :)

Elle est un des piliers du CSS Working Group et cette série d’articles est une plongée unique dans l’un des groupes de travail du W3C les plus actifs et les plus emblématiques du travail de standardisation du consortium. Loin des clichés et des idées reçues, c’est une occasion unique de mieux comprendre le long travail des ces hommes et femmes de l’ombre qui œuvrent au W3C.

Ces articles ont été traduits par Jérémie Patonnier et Frédéric Bourgeon avec l’aimable autorisation de Fantasai. Nous les publierons dans les semaines qui viennent, pour vous mettre en appétit voici le premier article qui donne le sommaire des suivants…

Lire la suite

mardi, 19 juin 2012

BrowserID, implémentation en Java côté serveur

Il y a quelque temps Pierre Rudloff publiait un billet présentant BrowserID et expliquant comment mettre en place cette technologie. Je l’ai implémentée dans un de mes projets qui utilise du Java côté serveur (le framework Play!, pour être précis). Comme Pierre ne présentait le code serveur qu’en  […]

Lire la suite

mercredi, 13 juin 2012

Thunderbird Test Day

C’est jeudi et ce n’est pas ravioli :-) (Je tiens à préciser que cette phrase inepte n’est pas de moi mais de Ludovic Hirlimann… voila, c’est dit, c’est fait :P) Jeudi toute la journée, la communauté des utilisateurs de Thunderbird, le logiciel libre de messagerie de la fondation Mozilla, organise  […]

Lire la suite

lundi, 21 mai 2012

Le futur des animations sur le Web

À la demande de Clochix, voici un petit état des lieux rapide des discussions liées aux animations Web au sein du W3C. C'est aussi une occasion de voir comment se construit un standard Web.

Lire la suite

mercredi, 16 mai 2012

BrowserID

De plus en plus de sites utilisent des systèmes de connexion sans mot de passe comme Facebook Connect ou OpenID. Ces systèmes permettent à l'utilisateur de se connecter rapidement en un ou deux clics. Mozilla a sorti il y a quelque temps BrowserID[1], un système de connexion similaire, simple à  […]

Lire la suite

- page 1 de 2