Archives du mot-clé ES6

JavaScript : les nouvelles méthodes sur l’objet Array apportées par ES6/ES2015

ES5 a apporté de nouvelles méthodes à l’objet Array que j’avais abordés dans un article précédent. La nouvelle version ES2015 (anciennement ES6) apportent également quelques nouveautés que nous allons voir.

Array.prototype.find

La méthode find() permet de retourner le premier élément d’un tableau respectant une condition via une fonction passée en paramètre. Si aucun element ne satisfait le critère, undefined est retourné.

const numbers = [1, 2, 3, 4, 5, 6];
let estPair = function (n) {
    return n % 2 === 0;
};
let firstEven = numbers.find(estPair); //2

La documentation sur MDN

Array.prototype.findIndex

findIndex() est identique a find à la différence qu’elle retourne l’index du premier élément à la place de l’élément lui même. Si aucun element ne satisfait le critère, -1 est retourné.

const numbers = [1, 2, 3, 4, 5, 6];
let estPair = function (n) {
    return n % 2 === 0;
};
let firstEvenIndex = numbers.findIndex(estPair); //1

La documentation sur MDN

Array.prototype.entries

La méthode entries() retourne un nouvel itérateur (Array Iterator) qui contient les clés/valeurs pour chaque index du tableau.

const arr = ['a', 'b', 'c'];
for (let item of arr) {
    console.log(item); // => 'a' 'b' 'c'
}
for (let pair of arr.entries()) {
    console.log(pair); // => [0, 'a'] [1, 'b'] [2, 'c']
}

La documentation sur MDN

keys

La méthode keys() retourne un nouvel itérateur (Array Iterator) contenant les clés pour chaque index du tableau.

const arr = [1, 2, 3];
const arrIterator = arr.keys();
let nextVal
while (nextVal = arrIterator.next().value) {
 console.log(nextVal);
}
// => 1
// => 2
// => 3

La documentation sur MDN

Array.of

La méthode (statique) Array.of() créé une nouvelle instance d’un tableau contenant les valeurs passés en paramètres, quelque soit le type ou le nombre de paramètres.

Array.of(1); // => [1]
Array.of(1,2,3); // => [1,2,3]

La documentation sur MDN

Array.from

La méthode (statique) Array.from() créé une nouvelle instance d’un tableau à partir d’un objet assimilés à un tableau array-like (comme arguments ou des noeuds du DOM) ou d’un objet iterable.

On peut utiliser Array.from() depuis arguments, des éléments du DOM, Map, Set, String…

// Array-like object (arguments) to Array
function f() {
  return Array.from(arguments);
}

f(1, 2, 3); 
// [1, 2, 3]

// Any iterable object...
// Set
var s = new Set(["foo", window]);
Array.from(s);   
// ["foo", window]

// Map
var m = new Map([[1, 2], [2, 4], [4, 8]]);
Array.from(m);                          
// [[1, 2], [2, 4], [4, 8]]  

// String
Array.from("foo");           
// ["f", "o", "o"]

// Using an arrow function as the map function to
// manipulate the elements
Array.from([1, 2, 3], x => x + x);      
// [2, 4, 6]

// Generate a sequence of numbers
Array.from({length: 5}, (v, k) => k);    
// [0, 1, 2, 3, 4]

La documentation sur MDN

ES7 / ES2016

La version 7 ou 2016 devrait également apportés d’autres nouveautés (encore en cours de validation …).

Liens

La page MDN sur l’objet Array
Une présentation sur l’utilisation des tableaux et objets : Working with Arrays and Objects in modern JavaScript (les slides) et la vidéo :

Il existe des polyfills pour ces méthodes. Vous pouvez également utiliser underscore ou lodash qui propose ses méthodes depuis un moment et bien d’autres .. (la documentation concernant les Arrays de underscore).

Angular : Utiliser les classes ES6

J’ai présenté dans un article précédent comment utiliser Babel afin de coder en ES6/ES2015 et transpiler vers ES5.

Angular 2 a été annoncé il y a 1 an à la ng-conf Europe et est aujourd’hui en version bêta. Cette nouvelle version est une réécriture complète qui va changer beaucoup de choses (plus de scope, controlleur, angular.modules, …). La version 1.x d’Angular a 5 ans et beaucoup de choses ont évolués depuis. 3 changements majeurs expliquent ce choix :

Pour info, il sera possible de coder pour la version 2 en ES5, ES6 ou TypeScript (et même dart).

Si vous décider de coder en ES6 ou Typescript, vos services ou vos composants seront des classes ES6. Celles-ci simplifient grandement l’écriture et leur utilisation dans Angular 1.x facilitera la migration vers la version 2.

Voyons maintenant comment utiliser les classes ES6 pour Angular. Les exemples suivants proviennent de mon application de Volley disponible sur github.

Commun

Vos services, controller, directives vont être définis comme des classes et l’injection va se passer par le constructeur. Il va falloir « enregistrer » vos dépendances sur votre objet (sur this) afin de pouvoir les utiliser dans vos méthodes. Attention, on oublie facilement le this !!

Controller

L’utilisation des classes ES6 n’empêchent pas d’utiliser $scope mais la migration en classe est un bon moyen de migrer vers la syntaxe « controller as ». Cette syntaxe n’utilise pas le scope qui n’existe pas en Angular 2.

Avant
Après

Services

Vous savez qu’il y a différent types de service en Angular : services, factory, provider.

Les services de type service sont conçus pour définir un service sous forme de classe (ou comme type instantiable)
Si vous avez des factory, le plus simple est de les convertir en service.

Dans le cas d’un provider, il faut que la classe contienne une propriété nommée $get, qui doit être une fonction qui retourne une factory.

Avant
Après

Directives

Les directives sont les éléments les plus complexes et les plus difficiles à appréhender en Angular 1.x. Attention contrairement aux autres types, il vous faudra instancier vous même vos services.

Avant
Après

Cet exemple n’a aucune dépendance injectée. Si votre directive contient des dépendances il faut les passer en paramètre lors de instanciation de votre directive.

Conclusion

Les classes ES6/2015 permettent de simplifier le code et facilitera une potentielle migration vers Angular 2.
Cet article n’utilise que les classes ES6 mais il est possible d’utiliser d’autres nouveautés comme les modules ou les décorateurs par exemple. Vous trouverez plus d’informations dans les liens ci dessous.

Liens

Angular 2 :

ES6 : quelques nouveautés de la prochaine version de JavaScript – Part III

Cet article est la suite d’une série d’articles sur ES6 :

Avant de commencer, une petite information en terme de nommage, ES6 a été renommé en ES2015.

Promise

Définissons tout d’abord ce qu’est une promesse :
Une promesse représente l’éventuel résultat d’une opération asynchrone

La notion de promise (promesse en français) n’est pas nouvelle et existe dans différentes librairies sous différentes formes comme :

Les Promise seront inclus de manière native dans ES6.

Les promise permettent de gérer plus facilement les méthodes asynchrones et d’éviter un code difficile à lire et maintenable si on utilise des callback. En effet on arrive facilement à avoir du code comme cela :

step1(function (value1) {
    step2(function (value2) {
        step3(function (value3) {
            step4(function (value4) {
                step5(function (value5) {
                    step6(function (value6) {
                        // Do something with value6
                    });
                });
            });
        });
    });
});

C’est ce qu’on appelle pyramid of doom ou callback hell.

Un nouvel objet Promise est introduit dans ES6. Le constructeur prend en paramètre une fonction avec 2 fonctions en paramètre : resolved et reject. La fonction resolve est à appeler si il n’y a pas eu d’erreur avec les valeurs de retour. Elle permet d’indiquer que la promise est résolue permettant la suite des actions. La fonction reject est à appeler si une erreur est survenue.

Création d’une Promise

    var promise = new Promise(
        function (resolve, reject) { // (A)
            ...
            if (...) {
                resolve(value); // success
            } else {
                reject(reason); // failure
            }
        });

Une fois notre promise définie, nous allons pouvoir définir un handler sur cette promise afin de réaliser des actions sur la future valeur. L’enchaînement des actions se fait via la méthode then. Cette fonction prend en paramètre 2 fonctions: la 1ere pour le succès (resolve) et la deuxième lors d’une erreur (reject). Les erreurs peuvent être également gérés via la méthode catch.

Utilisation d’une promise

 httpGet('http://myServer.com/file.txt')
    .then(
        function (value) { //Success
            console.log('Contents: ' + value);
        },
        function (reason) { //Error
            console.error('An error occurred', reason);
        });

L’avantage des promises est qu’on peut facilement les chaîner, ou les composer.

Fetch, la nouvelle API pour faire des appels Ajax utilise les promises. (un article pour aller plus loin)

Il existe des polyfills afin de pouvoir les utiliser dès maintenant :

Quelques liens sur le sujet :

Destructuring

Le destructuring permet d’initialiser des variables en les extrayant à partir d’objet existant.

//Array : on extrait 3 variables m, d et y à partir d'un tableau
var [m, d, y] = [12, 21, 1981]; 

//object : on extrait les propriétés d'un objet
//Ici on définit une fonction qui extrait la liste des classe CSS d'un élément
var listOfCLass = function ({ classList } ) {
    Array.from(classList).forEach( (item) => console.log(item))
};
listOfCLass(document.body);

Une autre utilisation avec un module quand on ne veut importer qu’une partie d’un module. (cf chapitre module dans la partie II).

Quelques liens :

ES7

La future version d’EcmaScript est déjà en préparation et je vais parler de 2 des nouveautés qui sont à mes yeux les plus intéressantes.

Object.observe

Object.observe() est une nouvelle API qui permet de s’abonner aux changements effectués sur un objet. A chaque modification sur l’objet, un événement sera lancé contenant la liste des changements (ajout d’une propriété, modification d’une valeur, suppression d’une propriété) sur l’objet.

Voici un exemple tirée de la documentation de Object.observe sur MDN :

var obj = {
  foo: 0,
  bar: 1
};

Object.observe(obj, function(changes) {
  console.log(changes);
});

obj.baz = 2;
// [{name: 'baz', object: <obj>, type: 'add'}]

obj.foo = 'hello';
// [{name: 'foo', object: <obj>, type: 'update', oldValue: 0}]

delete obj.baz;
// [{name: 'baz', object: <obj>, type: 'delete', oldValue: 2}]

Cela permet notamment de facilement mettre en place du data-binding (Angular 2 l’utilise afin d’améliorer les performances et éviter le « dirty checking »).

Quelques liens sur le sujet :

Async/Await

ES6 simplifie, via l’introduction des promesses, grandement la gestion de code asynchrone. Async va encore plus loin afin de faciliter la lecture et la compréhension.
ES7 introduit 2 nouveaux mots clés : async et await.

async permet de définir une fonction comme étant asynchrone alors que await permet d’indiquer que l’on souhaite bloquer l’exécution du code jusqu’au retour de la fonction.

Voici un exemple d’utilisation :

async function getUserName() {
    return 'royto';
}

async function displayLogoutMessage() {
    var user = await getUserName();
    alert(`GoodBye ${user} !`);
}

Pour ceux qui viennent du monde .NET cette syntaxe ne devrait pas les surprendre 🙂

Quelques liens :

Liens sur ES6 / ES2015

JavaScript : Utiliser ES6 maintenant avec Babel

Je vous ai parlé dans des articles précédent de la nouvelle version de JavaScript, ES6/ES2015, Harmony.
J’avais évoqué des outils afin de pouvoir utiliser ces nouveautés dés maintenant, malgré le support partiel dans les navigateurs ou dans de vieux navigateurs.

Babel est transpileur qui va transformer du code ES6 en code compatible ES5 (version compatible dans la plupart des navigateur (IE ….). Babel est la fusion de 2 projets : 6to5 et esnext.

Il supporte l’ensemble des nouveautés de ES6 et même certaines fonctionnalités de ES7. Il a l’avantage de produire un code compréhensible et ne nécessite pas l’inclusion d’un script additionnel dans votre page (comme traceur, un autre transpileur).

Babel est basé sur node et il existe des plugins pour la plupart des task runner JavaScript comme Grunt, Gulp, …

Voyons comment l’utiliser avec grunt.

Installation et utilisation

Tout d’abord, installons le package grunt pour babel. L’installation se fait via la commande :

npm install grunt-babel --save-dev

Nous définissons une tache nommée babel dans notre Gruntfile.js, qui va prendre nos fichiers écrit en ES6 et les transpiler en ES5.

J’ai configuré une tache avec 2 configurations, une pour le dev et une pour générer un package, dist.

 //transpilation to ES5
  babel: {
    options: {
      sourceMap: true,
      blacklist: ["strict"]
    },
    dev: {
      files: [{
        expand : true,
        cwd: '<%= yeoman.app %>/scripts/',
        src: ['**/*.js'],
        dest: '<%= yeoman.dist %>/scripts/',
        ext: '.js'
      }]
    },
    dist: {
      files: [{
        expand : true,
        cwd: '<%= yeoman.tmp %>/concat/scripts',
        src: '*.js',
        dest: '<%= yeoman.tmp %>/concat/scripts',
        ext: '.js'
      }]
    }
  }

Il est possible d’activer des options. Dans mon cas, j’ai activé les sourcesmaps et supprimé l’option strict qui rajoute les « use strict » en début de fichier (ils sont déjà présent dans mes fichiers).

Il nous faut maintenant l’inclure dans nos taches grunt. Je l’inclus dans ma tache serve qui permet d’avoir un serveur web.

  grunt.registerTask('serve', function (target) {
    if (target === 'dist') {
      return grunt.task.run(['build', 'connect:dist:keepalive']);
    }

    grunt.task.run([
      'clean:server',
      'bowerInstall',
      'concurrent:server',
      'autoprefixer',
      'copy:dist',
      'babel:dev',
      'connect:livereload',
      'watch'
    ]);
  });

Bien entendu, nous pouvons configurer grunt pour transpiler notre code à la volée et recharger la page via watch et livereload pour un process de développement plus fluide :

 watch: {
  js: {
    files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
    tasks: ['newer:eslint:all', 'newer:babel:dev'],
    options: {
      livereload: true
    }
  },
  //others file types ...
}

Exemple de Code généré

Voici du code ES6 que nous allons transpiler avec babel (let, expression lamda, string templates, classes)

//Exemple avec une expression lambda
var double = x => x * 2;

//string template
var deux = 2;
let quatre = double(deux);
console.log(`${quatre} est le double de 
            ${deux}`);

//Exemple avec une classe
class Person {
  constructor(firstname, lastname) {
    this.firstname = firstname;
    this.lastname = lastname;
  }
  fullname() {
    return this.firstname + ' ' + this.lastname; 
  }
}

let julien = new Person('Julien', 'Roy');
console.log(julien.fullname());

Et voici le code généré par Babel

//Exemple avec une expression lambda
'use strict';

var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }

var double = function double(x) {
  return x * 2;
};

//string template
var deux = 2;
var quatre = double(deux);
console.log('' + quatre + ' est le double de \n            ' + deux);

//Exemple avec une classe

var Person = (function () {
  function Person(firstname, lastname) {
    _classCallCheck(this, Person);

    this.firstname = firstname;
    this.lastname = lastname;
  }

  _createClass(Person, [{
    key: 'fullname',
    value: function fullname() {
      return this.firstname + ' ' + this.lastname;
    }
  }]);

  return Person;
})();

var julien = new Person('Julien', 'Roy');
console.log(julien.fullname());

Liens

  • REPL: une page qui permet de tester la conversion de votre code

ES6 : quelques nouveautés de la prochaine version de JavaScript – Part II

Cet article est la suite de ES6 : quelques nouveautés de la prochaine version de JavaScript.

Modules

La gestion de modules/dépendances est un vrai manque dans JavaScript. Des solutions comme AMD ou CommonJs ont permis de combler ce manque. La nouvelle version de JavaScript apporte une gestion native des modules.

Un module est défini dans un fichier. Les fonctions de ce fichier ne sont pas visibles des autres fichier à moins de les exporter explicitement. Cela se fait via l’introduction de 2 nouveaux mots clés : import et export. Export permet de définir ce que vous voulez exposer. A l’opposé,  import permet de d’importer tout ou partie d’un module.

Déclarons un fichier utils.js qui contient une fonction permettant de générer un Uuid

function generateUUID () {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r &amp;amp; 0x3 | 0x8);
        return v.toString(16);
    });
};

export { generateUUID }

Importons la méthode generateUUID dans un autre module

import { generateUUID } from 'utils';

var uuid = generateUUID();

On peut même importer le module complet

import 'utils' as utils;
 
console.log(utils.generateUUID());

Quelques liens pour aller plus loin :

Angular 2.0 utilisera les modules ES6.

Classes

ES6 apporte la gestion des classes via le mot clé class (avec d’autres comme constructor et extends). JavaScript est déjà objet via les prototypes mais peu de gens savent les utiliser.
Les nouveaux mots clés sont juste du « sucre syntaxique » au dessus des prototypes afin de faciliter l’écriture sous forme de classes, plus familier des personnes venant de Java, C#, ….

Pour ceux qui s’intéressent au développement objet via les prototypes, je conseille la présentation de Christophe Porteneuve, portant notamment sur les prototypes, à Paris Web : slides et vidéo.

Voici un exemple de la définition d’une classe Employee héritant de Person.

class Person {
    constructor(firstName, lastName, age) { //constructors!
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }

    fullName(){
        console.log(this.firstName + &amp;quot; &amp;quot; + this.lastName);
    }
}

class Employee extends Person { //inheritance
    constructor(firstName, lastName, age, salary) {
        super(firstName, lastName, age); //call the parent constructor with super
        this.salary = salary;
    }

    printSalary(){
        console.log('Salary : ' + this.salary);
    }
}

let julien = new Employee('Julien', 'Roy', '33', 150000);

julien.fullName();
julien.printSalary();

Quelques liens pour aller plus loin avec les classes ES6.

Améliorations sur les objets

ES6 apporte également des raccourcis concernant la création d’objet concernant :

la création de méthode

//ES5
var obj = {
        myMethod: function () {
            ···
        }
    };
//ES6
var obj = {
        myMethod() {
            ···
        }
    };

les propriétés

Il n’est plus necessaire de spécifier la valeur si on créer une propriété à partir d’une variable.

let x = 4;
let y = 1;
let obj = { x, y }; //ES6
let es5Obj = { x : x; y : y};

Computed property keys

Il est maintenant possible de créer des propriétés ayant une clé composé lors de la création d’un objet.

let obj = {
        [propKey]: true,
        ['b'+'ar']: 123
    };

De nouvelles méthodes sont également disponible :

Object.is()

Object.is permet une comparaison supprimant des cas bizarres en js lors des comparaison avec ===

(NaN !== NaN) //false 
-0 === +0 //false
var isSame = Object.is(value1, value2);

Object.assign()

La méthode assign permet la copie les propriétés d’un objet source dans un autre objet (idéal pour les options par défaut ou le clone d’objet).
Cette méthode existait dans plusieurs librairies comme $.extend en jQuery ou _.defaults pour Underscore/lodash.

Exemple de copie d’un objet avec Object.assign()

var obj = { a: 1 };
var copy = Object.assign({}, obj);

Quelques liens pour aller plus loin :

Symbols

ES6 apporte un nouveau type primitif : les Symbols. Ils sont uniques (2 symbols ne sont jamais égaux) et immutables (non modifiables). Ils peuvent être utilisés pour définir une propriétés d’un objet par exemple (on utilisera la méthode Object.getOwnPropertySymbols() pour obtenir les propriétés de type symbole d’un objet).

//Création d'un symbol
let symbol1 = Symbol();

//Utilisation d'un symbol comme propriété d'un objet
const MY_KEY = Symbol();
let obj = {
    [MY_KEY]: 123
};

Quelques liens sur le sujet :

Références

Quelques liens en complément de ceux de l’article précédent :

la suite au prochain épisode …

ES6 : quelques nouveautés de la prochaine version de JavaScript

JavaScript est basé sur la norme EcmaScript. La version 6, appelée Harmony, va apporter beaucoup de nouveautés qui vont améliorer et combler certains manques du langage.
Voici quelques améliorations que je trouve très intéressantes :

let

Let est le nouveau var. Il permet de déclarer une nouvelle variable mais avec un scope (portée) local contrairement à var.

Ainsi avec var, la portée est soit globale soit liée à la fonction dans laquelle celle-ci est définie. Let permet d’avoir une granularité plus fine (for, if, …) comme il l’est dans d’autres langages.

var t = 1;
if (true) {
  let t = 3;
  for (; t <= 5; t++) {
  	console.log(t);
  }
}
console.log(t);

// 3
// 4
// 5
// 1

Le lien vers la documentation de let sur MDN et un article complet sur le sujet : Variables and scoping in ECMAScript 6

Arrow functions

Les Arrow function est une nouvelle façon de définir des fonctions, un peu comme les expressions lambda en C#. Cela peut s’avèrer pratique dans le cas de définition de callback par exemple.

Une arrow function se définit via =>. La déclaration des paramètres se fait avant la flèche. Si il y a plusieurs paramètres, on entourera les paramètres par des parenthèses. Si l’expression est sur une ligne, celle-ci sera retournée. Si elle est sur plusieurs lignes, celle-ci doit être entourée d’accolades.

Voici un exemple d’un map avec une fonction qui met les valeurs au carré.

var myValues = [1,2,3,4,5];

var squared = myValues.map(x => x*x);
console.log(squared);  //-> [1, 4, 9, 16, 25]

//définition d'un function qui permet de déterminer si n nombre est pair
var even = (x) => x % 2 == 0;
var evenValues = myValues.filter(even);
console.log(evenValues);  //-> [2, 4]

var complex = (a, b) => {
    if (a > b) {
        return a;
    } else {
        return b;
    }
}

Le lien vers la documentation des arrow functions sur MDN.

Rest Parameters

Les rest parameters permettent de définir une fonction qui prend un  nombre infini de paramètres sous la forme d’un tableau.

On définit notre dernier paramètre comme étant un rest parameter en ajoutant … devant le nom du paramètre. Nous ne sommes plus obligé de passer par arguments. L’avantage étant ici que notre paramèter est nommé et qu’il s’agit d’un véritable array et qu’on peut donc lui appliquer ses méthodes spécifiques (reduce, sort, map, …).

On peut appeler notre méthode de 2 façons :

  • en passant la liste sous forme de paramètres à la suite les uns des autres
  • en passant la liste sous forme d’un tableau. Dans ce cas, il faut le préfixer par …

Voici un exemple (issue de la page MDN concernant les Rest Parameters et compléter avec l’appel sous forme de tableau)

function multiply(multiplier, ...theArgs) {
  return theArgs.map(function (element) {
    return multiplier * element;
  });
}

var arr = multiply(2, 1, 2, 3); 
console.log(arr); // [2, 4, 6]

var arr = multiply(2, ...[1, 2, 3]); 
console.log(arr); // [2, 4, 6]

Cela ressemble aux params en C#.

Default Parameters

ES6 va permettre de donner des valeurs par défaut aux paramètres de vos fonctions. Cela se fait comme dans d’autres langagues de la façon suivante :

function sayMsg(msg='This is a default message.') {
	console.log(msg);
}
sayMsg();
sayMsg('This is a different message!');

Le lien vers la documentation des default parameters sur MDN.

Array comprehension

Array comprehension est une nouvelle syntaxe pour créer des tableaux à parir de tableaux existant.

Pour cela on va utiliser la syntaxe suivante :

var square = [for (i of [ 1, 2, 3 ]) i*i ]; 
// [ 1, 4, 9 ]

var abc = [ 'A', 'B', 'C' ];
var lowChar = [for (letters of abc) letters.toLowerCase()];
// [ 'a', 'b', 'c' ]

//On peut rajouter des conditions
[for (i of [1, 2, 3, 4]) if (i > 3) i];
// [ 1, 2 ] 

//utiliser plusieurs tableaux
var cross = [for (i of [1, 2, 3]) for (j of [a, b, c]) i+j];
// [ '1a', '1b', '1c', '2a', '2b', '2c', '3a', '3b', '3c']

Le lien vers la documentation des Array comprehension sur MDN.

Generators

Les generators sont des itérateurs spéciaux qui permettent de récuperer la valeur suivante que lors de l’appel à next.

Il introduit le mot clé yield qui permet de définir la valeur retournée. Lors du permier appel à la fonction Generator, on récupère l’itérateur. La récupération d’une nouvelle valeur se fait via next(). Une exception StopIteration est lancée si il n’y pas de nouvelle valeur. Lors d’un appel à next, la fonction continuera son exécution à partir du dernier yield atteint.

Un Exemple tiré d’un article sur les Iterators et Generators sur MDN.

function simpleGenerator(){
  yield "first";
  yield "second";
  yield "third";
  for (var i = 0; i > 3; i++)
    yield i;
}

var g = simpleGenerator();
print(g.next()); // prints "first"
print(g.next()); // prints "second"
print(g.next()); // prints "third"
print(g.next()); // prints 0
print(g.next()); // prints 1
print(g.next()); // prints 2
print(g.next()); // StopIteration is thrown

Template Strings

Permet de définir des templates sous la forme de chaîne de caractères sans passer par une librairie externe (mustache, jsrender, …)

La définition d’un string template se fait via un ` (back tick). Les variables sont définies via ${ x } (x étant la variable).
Les templates string peuvent être définis sur plusieurs lignes (sans devoir faire de concaténation comme avec les strings).

let person = {name: 'Julien Roy'};
let tpl = `My name is ${person.name}.`;

console.log(tpl); //My name is Julien Roy

Autres nouveautés

Harmony apporte également d’autres nouveautés:

  • les classes
  • les modules
  • Mutation observers

Je parlerai dans un autre article de ces nouveautés très attendues.

Edit : le deuxième article sur les nouveautés de ES6.

Utilisation

Bien entendu, toutes ses nouveautés ne sont pas encore toutes intégrées dans les navigateurs, sachant que les spécifications ne sont pas encore figées et peuvent être amenées à évoluer. Il existe tout de même des outils qui permettent d’utiliser ces fonctionnalités comme des polyfills ou des transpileurs (compilation de code ES6 en ES5) comme Traceur ou 6to5. (les liens ci dessous ..)

Conclusion

ES6 apporte pas mal de nouveautés attendues par les développeurs qui vont permettre à JavaScript de combler certains manques et améliorer grandement son écriture pour en faire un langage « first class ». Pour information, la version 2.0 d’Angular est écrite en EcmaScript 6.

Références