Rapide historique Créé en 1995 sous le nom de Mocha puis LiveScript pour Mosaic HTTP Server Rapidement décliné en version client sous le nom de Javascript (Sun et Netscape étaient partenaires) Proposé à la standardisation à ECMA International en 1996, adopté et publié en 1997 (ECMA-262) Javascript : ES6
Rapide historique Implémentation par Microsoft sous le nom de JScript Quelques versions (ES2 et ES3 avec expr. régulières, try/catch, ...) en 98 et 99 … puis 10 ans d’hibernation avec une version 4 abandonnée ... Javascript : ES6
Rapide historique 2009, ES5 : JSON, mode strict , reflection, etc. Création (2008) puis normalisation (2009) du TC39, un comité technique formé par les principaux fabricants de navigateurs ES5 est le résultat de nombreux compromis, la wishlist des idées en cours est crée : “Harmony” Javascript : ES6
Rapide historique 2011 : Le TC39 commence à écrire la prochaine version 2011-2015 : Ecriture … 2015 : Publication de la première Release Candidate ! Javascript : ES6
Alors quoi de neuf dans ES6 ? Javascript : ES6
Les déclarations de variables Javascript : ES6
Jusqu’à ES5, pas de gestion du scope Javascript : ES6 for ( var i = ; i < 10 ; i ++ ) { // Quelque chose. } console .log (i); // => 10, i est défini dans tout le script/bloc
ES6 → nouvelles déclarations Javascript : ES6 for ( let i = ; i < 10 ; i ++ ) { // Quelque chose. } console .log (i); // => undefined Les déclarations let définissent des variables dont la portée est limité au bloc courant.
ES6 → nouvelles déclarations Javascript : ES6 let i = 'bonjour' ; for ( let i = ; i < 10 ; i ++ ) { console .log (i); // 1 2 3 ... 9 } console .log (i); // => bonjour Les déclarations let définissent des variables dont la portée est limité au bloc courant.
ES6 → nouvelles déclarations Javascript : ES6 const PI = 3.14 ; console .log (PI); // => 3.14 PI = 'circonférence d’un cercle' ; // Echoue de manière silencieuse. console .log (PI); // => 3.14 Les déclarations const définissent constantes nommées accessible uniquement en lecture. // Avec un objet : const params = { language: "JS" }; // => { language: 'JS' } params. language = "Ruby" ; // Effectue la modification (WTF?) console .log (params); // => { language: 'Ruby' } params = 5 ; // Echoue de manière silencieuse... console .log (params); // => { language: 'Ruby' }
La destructuration Javascript : ES6
La déstructuration Javascript : ES6 La déstructuration permet de définir des variables depuis un tableau ou un objet en utilisant une correspondance de motif (pattern matching).
La déstructuration Javascript : ES6 var mon_array = [ 'un' , 'deux' , 'trois' , 'quatre' ]; var [a, b, c, d] = mon_array; console .log (a, b, c, d); // => un, deux, trois, quatre // => Il est possible de “zapper” un élément var [un, , trois, quatre] = [ 'α' , 'β' , 'γ' , 'δ' ]; console .log (un, trois, quatre); // => α, γ, δ Exemple avec les tableaux :
La déstructuration Javascript : ES6 var mon_object = { a: 1 , b: 2 , c: 3 }; var { a: un, b: deux, c: trois} = mon_object; console .log (un, deux, trois); // => 1, 2, 3 // Marche aussi dans des objets imbriqués var mon_object = { a: 1 , b: { sous_b: 2 }, c: 3 }; var { a: un, b: { sous_b: deux}, c: trois} = mon_object; console .log (un, deux, trois); // => 1, 2, 3 Exemple avec les objets :
La déstructuration Javascript : ES6 var [a, b, c] = [1, 2]; console .log (a, b, c); // => 1, 2, undefined var [a] = []; console .log (a); // => undefined Gère les erreurs par une assignation à undefined :
La déstructuration Javascript : ES6 var [a, b, c = 'Hoy !' ] = [1, 2] ; console .log (a, b, c); // => 1, 2, 'Hoy !' var {a = 'Badger !' } = [] ; console .log (a); // => 'Badger !' … ou par une valeur par défaut spécifiée :
Les prototypes de fonctions Javascript : ES6
Valeurs par défaut Javascript : ES6 function defaulted (x, y = 'foobar') { console .log ({ x: x, y: y }); } defaulted(); // => { x: undefined, y: 'foobar' } defaulted( 42 ); // => { x: 42, y: 'foobar' } defaulted( 42 , 'es6' ); // => { x: 42, y: 'es6' } Les paramètres de fonctions peuvent avoir une valeur par défaut en cas de non-assignation
Les paramètres restants Javascript : ES6 function ma_fonction (arg1, ...leReste) { console .log (leReste); } ma_fonction(); // => [] ma_fonction( 1 ); // => [] ma_fonction( 1 , 2 ); // => [ 2 ] ma_fonction( 1 , 2 , 3 , 4 , 5 ); // => [ 2, 3, 4, 5 ] Les paramètres de fonctions peuvent être de nombre variable grâce à la syntaxe ...rest
Les paramètres restants Javascript : ES6 Cette syntaxe est différente par rapport au fait d’exploiter la variable arguments comme en ES5 : On peut exclure les n premiers paramètres (nommés) ...rest est un vrai tableau, plus besoin d’utiliser Array.prototype.slice.call(arguments) pour par exemple utiliser les structures de boucle (forEach, etc.)
Les propagation de paramètres Javascript : ES6 function ma_fonction (arg1, arg2, arg3) { console .log (` 1 : $ {arg1}, 2 : $ {arg2}, 3 : $ {arg3} `); } ma_fonction(); // => 1: undefined, 2: undefined, 3: undefined ma_fonction( 'rn' , 'Quizzard' , 'renater' ); // => 1: rn, 2: Quizzard, 3: renater ma_fonction(...[ 'test' , 'nouveautés' , 'es6' ]); // => 1: test, 2: nouveautés, 3: es6 // => Equivalent ES5 : // ma_fonction.apply(undefined, ['test', 'nouveautés', 'es6']); Les paramètres peuvent être passés par un tableau en utilisant une propagation (spread) :
Les fonctions “fléchées” (Arrow functions) Javascript : ES6
Les fonctions fléchées Exemples avec simple retour de valeur ou expression : Javascript : ES6 // Un argument parenthèses non nécessaires var est_pair = n => ! (n % 2 ); // Plusieurs arguments parenthèses nécessaires var est_superieur = (i, j) => i > j; console .log (est_pair( 259 )); // false console .log (est_pair( - 6 )); // true console .log (est_superieur( 1000 , 1 )); // true console .log (est_superieur( 5 , 5 )); //false
Les fonctions fléchées Exemple avec corps de fonction : Javascript : ES6 var reverse_string = str => { for ( var i = str. length - 1 , reversed = '' ; i >= ; reversed += str[i -- ]) { } return (reversed); }; console .log (reverse_string( '12345' )); // => 54321 console .log (reverse_string( 'Ce mec' )); // => cem eC
Les fonctions fléchées Exemple avec corps de fonction et x paramètres : Javascript : ES6 var reverse_strings = (...strings) => { var result = '' ; for ( var i = strings. length - 1 ; i >= ; i -- ) { for ( var j = strings[i]. length - 1 , reversed = '' ; j >= ; reversed += strings[i][j -- ]) { } result += reversed; } return (result); }; console .log (reverse_strings()); // => '' console .log (reverse_strings( '123' , '4' , '56' )); // => 654321
Les fonctions fléchées Avantage #2 : Un this lexical et non local En ES5, on rencontre souvent le “problème” de la valeur de this non/mal assignée : Javascript : ES6 //Methode 2 : Utiliser Function.prototype.bind(thisArg) function Voiture () { this .kilometres = 100 ; console .log ( this .kilometres); setTimeout (( function () { this .kilometres += 10 ; console .log ( this .kilometres); }).bind( this ), 2000 ); } new Voiture (); // => 100 ... 110 //Methode 1 : Utiliser une variable "self" ou "that" function Voiture () { var self = this ; self.kilometres = 100 ; console .log (self.kilometres); setTimeout ( function () { self.kilometres += 10 ; console .log (self.kilometres); }, 2000 ); } new Voiture (); // => 100 ... 110
Les fonctions fléchées Avantage #2 : Un this lexical et non local Les fonctions fléchées en es6 utilise un this lexical (celui du contexte ou elles sont définies) : Javascript : ES6 function Voiture () { this .kilometres = 100 ; console .log ( this .kilometres); setTimeout (() => { this .kilometres += 10 ; console .log ( this .kilometres); }, 2000 ); } new Voiture (); // => 100 ... 110
Les classes Javascript : ES6
Les classes Syntaxe : Javascript : ES6 class NomClasse extends ClasseParent { constructor(arguments) { //... } methode(arguments) { //... } get propriete() { return ...; } set propriete(valeur) { this ._propriete = valeur; } static methodeStatique() { //... } let instance = new NomClasse ( 'foobar' ); instance.methode([ 1 , 2 , 3 ]); instance.propriete = 5 ; NomClasse.methodeStatique();
Les classes Javascript : ES6 Gestion de l’héritage avec extends et super() class NomClasse extends ClasseParent Gestion des getters et setters avec les mot-clés get et set get propriete() {} Gestion des méthodes statiques avec le mot-clé static static method() {} En plus d’une syntaxe plus proche de la programmation OO, plusieurs avantages :
Sets Javascript : ES6 Valeurs uniques nativement Améliorations notables par rapport à la gestion en array : let set = new Set (); set. add ( 1 ) set.size // => 1 set. add ( 1 ) set.size // => 1
Sets Javascript : ES6 Recherche plus rapide / simple que .indexOf() Améliorations notables par rapport à la gestion en array : let set = new Set (); set. add ( 1 ) set. has (1); // => true let array = [1]; array. indexOf (1) !== -1 // => true
Sets Javascript : ES6 Suppression plus rapide / simple que .filter(), etc. Améliorations notables par rapport à la gestion en array : let set = new Set (); set. add ( 1 ) set. delete (1); let array = [1]; array. filter (function(n) { return (n !== 1); });
Sets Javascript : ES6 Assurance d’itérer dans l’ordre d’ajout Améliorations notables par rapport à la gestion en array : let set = new Set (); set. add ( 'a' ); set. add ( 'b' ); set. add ( 'c' ); for (let x of set) { console .log (x); } // => 'a', 'b', 'c', ce n’était pas forcément le cas avec ['a', 'b', 'c']
Maps Javascript : ES6 Les clés ne sont plus forcément des chaînes Améliorations notables par rapport à la gestion en objet : let map = new Map (), key = {}; map. set (key, 1 ); map. set (NaN, 42 ); map.has(key); // => true map.has({}); // => false : {} n’est pas === a key ! (deux objets différents)
Maps Javascript : ES6 Plus de risques de télescopage avec des propriété natives : Améliorations notables par rapport à la gestion en objet : let map = new Map (); map.get( 'toString' ); // => undefined map. set ( 'toString' , 42 ); map.get( 'toString' ); // => true var objet = {}; objet.toString; // => [function()] // On peut contourner en testant // objet.hasOwnProperty() objet.toString = 42 ; objet.toString; // => 42
WeakSet & WeakMap Javascript : ES6 Structure de données qui ne protège pas ses éléments contre le ramasse-miettes (Garbage Collector) Le Garbage Collector supprimera des éléments quand ils ne seront plus utilisés Protège contre les fuites de mémoires
WeakSet Javascript : ES6 let set = new Set (); let myKey = {}; set. add (myKey); ( function () { let myScopedKey = {}; set. add (myScopedKey); // => set contient 2 éléments })(); // => set contient toujours 2 éléments let set = new WeakSet (); let myKey = {}; set. add (myKey, 'Kawai !' ); ( function () { let myScopedKey = {}; set. add (myScopedKey); // => set contient 2 éléments })(); // => set contient 1 élément // => Le GC a néttoyé myScopedKey
WeakMap Javascript : ES6 let map = new Map (); let myKey = {}; map.set(myKey, 'Kawai !' ); ( function () { let myScopedKey = {}; map.set(myScopedKey, 42 ); // => map contient 2 éléments })(); // => map contient toujours 2 éléments let map = new WeakMap (); let myKey = {}; map.set(myKey, 'Kawai !' ); ( function () { let myScopedKey = {}; map.set(myScopedKey, 42 ); // => map contient 2 éléments })(); // => map contient 1 élément // => Le GC a néttoyé myScopedKey
Limitations de WeakSet & WeakMap Javascript : ES6 La volatilité des structures rend impossible l’itération sur ces objets .size() n’est pas disponible, dû également à la volatilité .clear() n’est pas disponible, c’est au GC de vider l’objet
Exemple : Des propriétés “privées” Javascript : ES6 let privates = new WeakMap (); class MaClasseBidon { constructor(foo, bar) { privates.set( this , { foo, bar }); } methodeBidon() { console .log (privates.get( this ).foo); console .log (privates.get( this ).bar); } } let instance = new MaClasseBidon ( 42 , {}); instance.methodeBidon(); // => 42, [Object] console .log ( Object .keys(instance)); // => []
Les symboles Javascript : ES6
Les symboles Javascript : ES6 Immuables Uniques Symbol( 'bonjours' ) === Symbol( 'bonjours' ); // => false Utilisés comme identifiant des propriétés d’objet obj[Symbol( 'bonjours' )] = 'blah blah' ; let mySymbol = Symbol( 'bonjours' ); let mySymbol2 = Symbol({}); let mySymbol3 = Symbol();
Les symboles Javascript : ES6 Permet d’éviter les conflits de noms let toString = Symbol( 'toString' ); let obj = { [toString]() { // The native toString method is not overwritten return ( 'Ok !' ); } }; obj. toString (); // => [object Object] console .log (obj[toString]()); // => “Ok !”
Les symboles Javascript : ES6 Assure une “confidentialité” des propriétés var obj = ( function () { let prop = Symbol( 'notYourStuff' ); let returned; returned = { [prop] : 42 }; console .log (returned[prop]); // Dans le scope, on peut accéder à la propriété return (returned); })(); obj[prop]; // => Erreur prop n'est pas définie // Hors du scope, on ne peut PAS accéder à la propriété JSON.stringify(obj); // => {} // La propriété est ignorée par JSON.stringify()
Itérateurs & nouvelle structure de boucle Javascript : ES6
Les itérateurs Javascript : ES6 Objet pouvant être parcourus (itérés) Implémentent les interfaces Iterable , Iterator et IteratorResult : interface Iterable { [Symbol.iterator](): Iterator } interface Iterator { next(): IteratorResult; } interface IteratorResult { done: boolean ; value: any; }
Les itérateurs Javascript : ES6 Lancement de l’itération Iterable. [Symbol.iterator]() => Iterator Iterator.next() => IteratorResult IteratorResult.done ? valeur = IteratorResult.value Fin de l’itération Récupération d’un valeur de l’itération false true
Les itérateurs Javascript : ES6 let fibonacciDe10 = { [Symbol.iterator]() { let precedent = , actuel = 1 , tour = ; return { next() { [precedent, actuel] = [actuel, precedent + actuel]; tour ++ ; return { done: tour > 10 , // false, puis true au 10ème tour value: actuel // 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 } } } } }
Itérateurs pour les types natifs Javascript : ES6 let monTableau = [ 1 , 2 , 3 ]; console .log (monTableau[ Symbol.iterator ]); // => [function] let iterator = monTableau[Symbol.iterator](); console .log (iterator); // => [object] console .log (iterator. next ); // => [function] console .log (iterator. next (). value ); // => 1 console .log (iterator. next (). value ); // => 2 console .log (iterator. next (). value ); // => 3 console .log (iterator. next (). value ); // => undefined // => Mais .done = true !
Boucle pour itérateurs Javascript : ES6 Syntaxe “for…of” : for (variable of iterator) { /*...*/ } Permet de “consommer” les objets itérateurs Itère sur les les valeurs et non les clé (for...in)
Boucle pour itérateurs Javascript : ES6 for (let i of fibonacciDe10) { console .log (i); // 1, puis 2, 3, 5, 8, 13, 21, // 34, 55, et enfin 89 }
Boucle pour itérateurs Javascript : ES6 let monTableau = [ 1 , 2 , 3 ]; for (let i of monTableau) { console .log (i); // => 1, puis 2, puis 3 } let monObjet = { a: 1 , b: 2 , c: 3 }; for (let i of monObjet) { console .log (i); }
Les générateurs Javascript : ES6
Les générateurs Javascript : ES6 Les itérateurs sont très utiles mais syntaxe complexe Les générateurs rendent la syntaxe plus simple Nouveaux mots-clés : function* generator(); yield value; yield* secondGenerator();
Les générateurs Javascript : ES6 Un générateur est une fonction qui retourne automatiquement un objet Iterable Définis en utilisant la syntaxe function* gen() {} Les valeurs à retourner sont envoyées via yield value;
Les générateurs Javascript : ES6 function * fibonacciDe10(){ let precedent = , actuel = 1 , tour = ; while (tour < 10 ) { [precedent, actuel] = [actuel, precedent + actuel]; yield actuel; tour ++ ; } } let iterator = fibonacciDe10(); console .log (iterator[Symbol.iterator]); // [object] console .log (iterator[Symbol.iterator]. next ); // [function] for (let i of fibonacciDe10()) { console .log (i); } // 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
Délégation de générateurs Javascript : ES6 function * subGen(){ yield 'c' ; yield 'd' ; } function * gen(){ yield 'a' ; yield 'b' ; yield * subGen(); yield 'e' ; } for (let i of gen()) { console .log (i); } // 'a', 'b', 'c', 'd', 'e'
Les promesses Javascript : ES6
Les promesses Javascript : ES6 Une promesse représente un objet dont on ne connaît pas encore la valeur Nouvelle façon de gérer les opérations asynchrone Une promesse a 3 états possibles : en cours, puis accomplie _ou_ rejetée Les états accomplie ou rejetée sont alors immuables
Les promesses Javascript : ES6 Syntaxe simple : let maPromesse = new Promise ( function (resolve, reject) { // Code resolve(valeur); // _OU_ reject(erreur); } maPromesse() .then( function (valeur) { // ... }) . catch ( function (erreur) { // ... });
Les promesses Javascript : ES6 Chaînables et mixables : maPromesse1 () . then ( maPromesse2 ) . then ( maPromesse3 ) . then ( maPromesse4 ) . then ( maPromesse5 ) . catch ( function ( erreur ) { // Une erreur est survenue // dans une des promesses // (rejetée) }) maPromesse1 () . then ( maPromesse2 ) . then ( maPromesse3 ) . then ( function () { // Du code pas asynchrone }) . then ( maPromesse4 ) . then ( maPromesse5 ) . catch ( function ( erreur ) { // ... })
Les promesses Javascript : ES6 Asynchrone : let maPromesse = new Promise ( function (resolve, reject) { setTimeout ( function () { console .log ( 'Après 5 secondes' ); resolve(); }, 5000 ); console .log ( 'Dans la promesse' ); }); console .log ( 'Avant la promesse' ); maPromesse().then( function () { console .log ( 'Dans le then()' ); }); console .log ( 'Après la promesse' ); // 'Avant la promesse' // 'Après la promesse' // 'Dans la promesse' // … 5 secondes passent ... // 'Après 5 secondes' // 'Dans le then()'
Les promesses Javascript : ES6 get( '/monUrl' , function (data, err) { if (err) { } get( '/monUrl2' , function (data, err) { if (err) { } get( '/monUrl3' , function (data, err) { if (err) { } get( '/monUrl4' , function (data, err) { if (err) { } //... etc }); }); }); }); get( '/monUrl' ) .then(get( '/monUrl2' )) .then(get( '/monUrl3' )) .then(get( '/monUrl4' )) . catch ( function (err) { console .log (err); }); Supprime le “callback hell” ou code pyramidal :
Les modules Javascript : ES6
Les modules Javascript : ES6 Programmation modulaire permettant d’isoler des composants dans des fichiers Hérite des syntaxes déjà utilisées (AMD, CommonJS) Modèle asynchrone, aucun code n’est exécuté tant que le module n’est pas chargé et exécuté
Les modules Javascript : ES6 // lib/malib.js export const PI = 3.14 ; export function * fibonacciDe10(){ let precedent = , actuel = 1 , tour = ; while (tour < 10 ) { [precedent, actuel] = [actuel, precedent + actuel]; yield actuel; tour ++ ; } } // index.js import * as malib from "lib/malib" ; console .log (malib.PI); // 3.14 for (let i of malib.fibonacciDe10()) { // 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 } // index2.js import PI from "lib/malib" ; console .log (PI); // 3.14 // index3.js import {fibonacciDe10 , PI} from "lib/malib" ; // ... Syntaxe :
Les modules Javascript : ES6 // lib/otherLib.js export * from 'lib/malib' ; export var maVar = 42 ; // index.js import * from 'lib/otherLib' ; console .log (PI); // 3.14 console .log (maVar); // 42 // lib/otherLib2.js export default function () { console .log ( 'Coucou' ); } var uglyLocalName = 42 ; export { uglyLocalName as foo}; // index.js import * as otherLib from 'lib/otherLib2' ; otherLib.unexistantName(); // 'Coucou' console .log (otherLib.foo); // 42 Délégation d’import / Default / Aliases :
La gestion des chaînes de caractères Javascript : ES6
La gestion des chaînes de caractères String.prototype.includes(substring, startingAt) String.prototype.startsWith(substring, startingAt) String.prototype.endsWith(substring, endingAt) Javascript : ES6
La gestion des chaînes de caractères Javascript : ES6 // String.prototype.includes(substring, startingAt) 'Hello world' .includes( 'wor' ) // true 'Hello world' .includes( 'hell' ) // false, sensible à la casse 'Hello world' .includes( 'Hello' , 1 ) // false, on commence à 1 // String.prototype.startsWith(substring, startingAt) '42, born to code' .startsWith( '42' ) // true '42, born to code' .startsWith( 'foo' ) // false '42, born to code' .startsWith( 42 , 1 ) // false, on commence à 1 // String.prototype.endsWith(substring, endingAt) '42, born to code' .endsWith( 'code' ) // true '42, born to code' .endsWith( 'born' ) // false '42, born to code' .endsWith( 'code' , 5 ) // false, on arrete à 5 // Exemple equivalent es5 String . prototype . startsWith = function (substring, startingAt) { startingAt = (startingAt) ? startingAt : ; return ( this . indexOf (substring) === startingAt); };
La gestion des chaînes de caractères Gestion des gabarits de chaînes de caractères : Javascript : ES6 `Simple chaîne` `chaîne avec saut de ligne au milieu` `chaîne avec $ {expression Javascript} évaluée` fonction_tag `chaîne ou $ {expression Javascript}`
La gestion des chaînes de caractères Gère les sauts de lignes nativement et protège des erreurs de guillemets : Javascript : ES6 // Avant on devait faire : var old_school = "Ligne 1 \n Ligne 2\n'\"" ; // Swag ! let new_school = `Ligne 1 Ligne 2 '" `;
La gestion des chaînes de caractères Gère les interpolation d’expressions Javascript : Javascript : ES6 let ma_variable = "bonjours" ; let ma_string = `Il y a toujours un "s" dans '${ma_variable}' `; // => Il y a toujours un "s" dans 'bonjours' `La variable est de type "${typeof ma_variable}" `; // => La variable est de type "string" `Le type de véhicule est '${vehicule.getType()}' `; // => Le type de véhicule est 'car'
La gestion des chaînes de caractères Gère les interpolation d’expressions Javascript … mais ! Javascript : ES6 let ma_variable = 10 ; console .log (`Ma variable = $ {ma_variable ++ }`); // => Ma variable = 10 console .log (ma_variable); // => 11 Attention donc aux appels de méthodes, etc.
La gestion des chaînes de caractères Gestion des étiquettes (tags) pour le taint checking, par ex : Javascript : ES6 let a = 2 ; let b = 5 ; console .log (`Normalement $ { a } plus $ { b } = $ {a + b}`); // "Normalement 2 plus 5 = 7" function tag (strings, ...values) { console .log (strings); console .log (values); return "J'ai plus envie de calculer" ; } console .log (tag`Normalement $ { a } plus $ { b } = $ {a + b}`); // ['Normalement ', ' plus ', ' = '] // [2, 3, 5] // "J'ai plus envie de calculer"
Merci ! Des question ? Pour me contacter : linkedin.com/in/jucrouzet github.com/jucrouzet twitter.com/c2c