BreizhCamp 2015

#BzhCmp

ES6 dès aujourd'hui 

#ES6Today #BzhCmp

BreizhCamp 2015

#BzhCmp

Grégory Houllier

Architecte Web, passionné par le Front-End

Co-Fondateur de @RennesJS

#ES6Today #BzhCmp

BreizhCamp 2015

#BzhCmp

#ES6Today #BzhCmp

Meetup le dernier jeudi de chaque mois

25/06/2015 à Epitech

EcmaScript

#ES6Today #BzhCmp

Version standardisée de Javascript

Actuellement en version 5.1 (2009)

ES6 c'est quoi?

Ensemble de nouvelles APIs et Syntaxes

#ES6Today #BzhCmp

++productivity && ++expressivity

Finalisé en Juin 2015

Harmony > ES6 > ES2015

Les influences

#ES6Today #BzhCmp

Langage transpilé en Javascript créé fin 2009 par Jérémy Ashkenas (créateur de Backbone et Underscore).

  • Classes
  • Arrow Functions
  • Rest+Spread

Les influences

#ES6Today #BzhCmp

Plateforme basée sur le moteur Javascript V8 de Chrome créé en 2009

  • Dynamisation de l'écosystème Javascript
  • Modules CommonJS

c'est quoi?

Un transpileur Javascript

#ES6Today #BzhCmp

 Anciennement 6to5, esnext

Transforme un code ES6 en code ES5 interprétable sous IE9+, FF19+, CH23+...

Sous le capot (1/2)

#ES6Today #BzhCmp

Parser

Transformer

Generator

Convertit le code Javascript en AST

Manipule l'AST

Convertit l'AST en Javascript

Sous le capot (2/2)

#ES6Today #BzhCmp

{
  type: "Program",
  body: [{
    type: "VariableDeclaration",
    kind: "var",
    declarations: [{
      type: "VariableDeclarator",
      id: { type: "Identifier", name: "foo" },
      params: [],
      body: [{
        type: "BlockStatement",
        body: [{
          type: "ReturnStatement",
          argument: { type: "Identifier", name: "bar" }
        }]
      }]
    }]
  }]
}

AST

var foo = function foo() {
  return bar;
};

ES5

AST: Abstract Synthax Tree

Pourquoi choisir           ?

#ES6Today #BzhCmp

Qui utilise           ?

#ES6Today #BzhCmp

  • Comme plugin de votre outil de build

    • Gulp, Grunt, Browserify, Webpack, ...
  • En ligne de commande

  • Directement dans le browser

  • Jouer avec sur babeljs.io/repl/

#ES6Today #BzhCmp

Plusieurs choix possibles:

Démarrer avec

#ES6Today #BzhCmp

# ProTip™ .bashrc
export PATH=$PATH:./node_modules/.bin

# Installation locale
npm install babel -S

# Transpiler vos sources ES6 en ES5
babel src/main.js -o dist/main.js

# Executer vos sources ES6
babel-node src/server.js

CLI

Démarrer avec

#ES6Today #BzhCmp

# Install dependencies
npm i -S browserify babelify watchify

# Browserify + debug
browserify src/main.js -t babelify --debug --outfile dist/bundle.js

# Watching
watchify src/main.js -t babelify --debug --outfile dist/bundle.js

CLI

Débugger avec

Démo

Les nouveautés ES6 

#ES6Today #BzhCmp

Question de timing on ne verra pas tout ...

Classes

Et non ... c'est juste du sucre synthaxique à l'approche prototypal

#ES6Today #BzhCmp

"Enfin!!! Moi qui avait rien compris aux prototypes ça tombe bien"

#ES6Today #BzhCmp

class Talk {
  constructor(date, subject) {
    this.date = date;
    this.subject = subject;
  }
  getDate() {
    return this.date;
  }
  getSubject() {
    return this.subject;
  }
  static isValid(talk) {
    return null !== talk.subject;
  }
}

Classes

function Talk(date, subject) {
  this.date = date;
  this.subject = subject;
}
Talk.prototype.getDate = function getDate() {
  return this.date;
};
Talk.prototype.getSubject = function getSubject() {
  return this.subject;
};
Talk.isValid = function isValid(talk) {
  return null !== talk.subject;
};

ES6

ES5

#ES6Today #BzhCmp

class JsTalk extends Talk {
  constructor(date) {
    super(date, 'JS');
  }
}

Classes

ES6

function _extends(child, parent) {
  function ctor() {
    this.constructor = child;
  }
  ctor.prototype = parent.prototype;
  child.prototype = new ctor();
  return child;
}

function JsTalk() {
  Talk.prototype.constructor.call(this, Date.now(), 'JS');
}
_extends(JsTalk, Talk);

ES3

function JsTalk() {
  Talk.prototype.constructor.call(this, Date.now(), 'JS');
}
JsTalk.prototype = Object.create(Talk.prototype);

ES5

#ES6Today #BzhCmp

Classes

Utilité: ★★☆☆

Support: 

  • Babel: 25/30
  • Browsers: FF 39+, (Chrome, Edge, io.js) w/ flag             

Limitations:

  • Pas de propriétés static
  • Attention à la chaine de résolution des prototypes
  • Pas de hoisting

Arrow Functions

#ES6Today #BzhCmp

super hero functions

#ES6Today #BzhCmp

// Verbose
var getTitle = (item) => {
  return item.title;
};

// Implicit return
var getTitle = (item) => item.title;

// Optional parenthesis
var getTitle = item => item.title;

Arrow Functions

ES6

#ES6Today #BzhCmp

function clicker(node) {
  this.counter = 0;
  node.addEventListener((event) => {
    // Lexical binding sur le context parent
    ++this.counter;
    arguments[0] === event; // false
    arguments[0] === node; // true
  });
}

Arrow Functions

ES6

#ES6Today #BzhCmp

Arrow Functions

Utilité: ★★★☆

Support: 

  • Babel: 9/11
  • Browsers: FF 39+

Limitations:

  • Ce ne sont pas des constructeurs (pas de new)
  • .call .apply et .bind ne change pas le this

Modules

#ES6Today #BzhCmp

"Plus d'excuses pour pourrir le scope global"

Fortement inspiré de CommonJS

#ES6Today #BzhCmp

// ./controller/home.js

export default class HomeController {
  ...
}


// ./main.js

import HomeController from './controller/home.js';

Modules

ES6

#ES6Today #BzhCmp

// ./utils.js

export function mixin() {
  ...
}

export const API_VERSION = 1;


// ./main.js

import * as utils from './utils';

utils.API_VERSION; // 1

Modules

ES6

#ES6Today #BzhCmp

// ./utils.js

function mixin() {
  ...
}

const API_VERSION = 1;

// Une instruction pour les exporter tous
export { mixin, API_VERSION };

Modules

ES6

#ES6Today #BzhCmp

Modules

Utilité: ★★★★

Support: 

  • Babel: 5/6*
  • Browsers: N/A 

Limitations:

  • Nécessite un encore contexte CommonJS (Node, Browserify, ...) meme avec Babel

Template Strings

backtick, un nouveau delimiter pour ne plus avoir à choisir entre simple et double quotes

#ES6Today #BzhCmp

"Fini la concaténation de chaines !!"

#ES6Today #BzhCmp

// Template simple
function text(messages) {
  return `you have ${ messages } message${ messages !== 1 ? `s` : `` }`;
}

// Template avancé
function html(list) {
  return `<ul>${list.map((item) => {
    return `<li>${item.value}</li>`;
  })}</ul>`;
}

Template Strings

ES6

#ES6Today #BzhCmp

// Evaluation
var welcome = `Welcome ${user} at Breizhcamp!`;
// user is not defined 


// Multi lines
var multilines = 
    `Header

    Content

    Footer`;

Template Strings

ES6

#ES6Today #BzhCmp

Template Strings

ES6

Et coté performance?

#ES6Today #BzhCmp

Template Strings

Utilité: ★★★★

Support: 

  • Babel: 3/3
  • Browsers: Chrome 43+, FF 38+, Edge, io.js

Object Literals

Propriétés raccourcies, méthodes, propriétés calculées

#ES6Today #BzhCmp

"Don't repeat yourself"

#ES6Today #BzhCmp

function todo() {}

var context = {
  // Raccourci
  todo,
  // Propriété calculée
  ['uniq' + Date.now()]: 'test',
  // Méthode
  toString() {
    return 'another value';
  }
};

Object Literals

ES6

#ES6Today #BzhCmp

Object Literals

Utilité: ★☆☆☆

Support: 

  • Babel: 6/6
  • Browsers: Chrome 44+, FF 38+, Edge, io.js

Rest, Spread, Default

#ES6Today #BzhCmp

"Une gestion des arguments aux petits oignons"

arguments

#ES6Today #BzhCmp

function log(level, ...messages) {
  console.log(`${level} ${messages.length} messages`);
}

log('warn');
//> warn 0 messages

log('debug', 'hello', 'breizhcamp', 2015);
//> debug 3 messages

Rest

ES6

#ES6Today #BzhCmp

var args = [
  'click',
  (event) => { console.log(event); },
  false
];

document.addEventListener(...args);

Spread

ES6

var args = [
  'click',
  function (event) { console.log(event); },
  false
];

document.addEventListener.apply(document, args);

ES5

#ES6Today #BzhCmp

function img(src, height = 100, width = 100) {
  return `<img src="${src}" height="${height}" width="${width}" />`;
}

img('avatar.png');
//> <img src="avatar.png" height="100" width="100" />

img('player.png', 50, 50);
//> <img src="player.png" height="50" width="50" />

Default

ES6

#ES6Today #BzhCmp

Rest, Spread, Default

Utilité: ★★★☆

Support: 

  • Babel: 19/21
  • Browsers: FF 38+, Edge

Limitations:

  • Rest n'est pas aussi puissant qu'en Coffee

Destructuring

#ES6Today #BzhCmp

"Prenez une aspirine..."

Extraction des variables d'un objet

#ES6Today #BzhCmp

// Object Destructuring
var node = document.querySelector('input[type=password]');
var { top, right, left, bottom } = getComputedStyle(node);

// Array Destructuring
var pattern = /(\d\d)\/(\d\d)\/(\d\d\d\d)/;
var value = '07/05/2015';
var [all, day, month, year] = pattern.exec(value);
// ou
var [, day, , year] = pattern.exec(value);

Destructuring

ES6

#ES6Today #BzhCmp

// Object Destructuring
var node = document.querySelector('input[type=password]');

console.log(node)
//> {
      name: 'mypassword',
      value: '1234',
      style: {
        top: 0,
        ...
      }
      ...
    }
var { name, value: password, style: { top } } = node;

Destructuring

ES6

var name = node.name;
var password = node.value;
var top = node.style.top;

ES5

#ES6Today #BzhCmp

// Parameters Destructuring + Default
function open({ src, readonly = true}) {
  console.log(src, readonly);
}

let src = '/tmp/user.json';

open({src, readonly: false});
//> '/tmp/user.json', false

open({src});
//> '/tmp/user.json', true

Destructuring

ES6

#ES6Today #BzhCmp

Destructuring

Utilité: ★★★☆

Support: 

  • Babel: 27/30
  • Browsers: Partiel dans FF 38+

Remarques:

  • Fortement intégré dans la syntaxe des modules

Generators

function* () {} // Return Generator

#ES6Today #BzhCmp

"Les machines à états, c'est mon dada"

#ES6Today #BzhCmp

function* workflow(initial = 0) {
  var step = initial;
  console.log('step', step);
  yield 'step' + step;

  ++step;
  console.log('step', step);
  yield 'step' + step;
}

var w = workflow(1);

w.next(); // {"done":false, "value":"step1"}
w.next(); // {"done":false, "value":"step2"}
w.next(); // {"done":true}

Generators

ES6

#ES6Today #BzhCmp

var app = require('koa')();
// x-response-time
app.use(function *(next){
  var start = new Date;
  yield next;
  var ms = new Date - start;
  this.set('X-Response-Time', ms + 'ms');
});
// logger
app.use(function *(next){
  var start = new Date;
  yield next;
  var duration = new Date - start;
  console.log(`${this.method} ${this.url} - ${duration}`);
});
// response
app.use(function *(){
  this.body = 'Hello World';
});
app.listen(3000);

Generators

Et dans la vrai vie?

#ES6Today #BzhCmp

Generators

Utilité: ★★★☆

Support: 

  • Babel: 20/21
  • Browsers: Partiel (FF 38+, Chrome 43+, Node 0.12)

Block declaration

Limiter la porter  d'une variable

Eviter les collisions de nommage

#ES6Today #BzhCmp

"let,const is the new var"

#ES6Today #BzhCmp

if (true) {
  let first = 0;
}
console.log(first, second);
//> first is undefined


if (false) {
  function test() {}
}
console.log(test);
//> test is undefined

const VERSION = 1.1;
VERSION = 2.0;
//> "VERSION" is read-only

Block declaration

ES6

#ES6Today #BzhCmp

Block declaration

Utilité: ★★☆☆

Support: 

  • Babel: 14/18
  • Browsers: Partiel (FF 38+, Chrome 43+, Node 0.12)

Remarques:

Les autres nouveautés

#ES6Today #BzhCmp

"Promise, Set, Map, WeakMap, Symbol, Proxy, for...of"

#ES6Today #BzhCmp

function after(delay = 1000) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, delay);
  });
}

after(100).then(() => {
  console.log('exectued after 100ms');
});

Promise

ES6

#ES6Today #BzhCmp

// Map fonctionne comme un dictionnaire
var map = new Map();
map.set('key', 'value');

// WeakMap permet d'utiliser un objet comme clé
var map = new WeakMap();
var key = new Date();
map.set(key, 'value');

// Set stock uniquement des valeurs
var set = new Set([1, 2, 3, 2, 3, 4]);
set.values()
//> [1, 2, 3, 4]

Set, Map, WeakMap

ES6

#ES6Today #BzhCmp

var Api = (function() {
  const secret  = Symbol('secret');
  const API_SECRET = 'ThisIsSecret';
  return class Api {
    constructor() {
      this[secret] = API_SECRET;
    }
    static isValid(Api) {
      return Api[secret] === API_SECRET;
    }
  }
}());

var api = new Api();
console.log(Api.isValid(api)); // true
console.log(Api.secret); // undefined

Symbol

ES6

#ES6Today #BzhCmp

// Proxying a normal object
var target = {};
var handler = {
  get: (receiver, name) => {
    return `Hello, ${name}!`;
  }
};
var p = new Proxy(target, handler);
p.world === "Hello, world!";

// Proxying a function object
var target = function () { return "I am the target"; };
var handler = {
  apply: (receiver, ...args) => {
    return "I am the proxy";
  }
};
var p = new Proxy(target, handler);
p() === "I am the proxy";

Proxy

ES6

Quelques liens

#ES6Today #BzhCmp

Questions?

#ES6Today #BzhCmp

Bonus: Aperçu d'ES7

#ES6Today #BzhCmp

"Async functions, Object.observe, autobind"