EcmaScript 6

A nova versão do Javascript

Francisco Gileno

  • Desenvolve projetos web desde 2000
  • 2013 - C.E.S.A.R. - Recife

EcmaScript

Linguagem de script padronizada pela ECMA International.

Javascript

Implementação do EcmaScript (Dialeto)

Breve Histórico

  • 1995 - Primeira versão, desenvolvida por Brendan Eich - Netscape. Mocha, LiveScript, JavaScript (10 dias)
  • 1996 - Microsoft lança JScript, com algumas melhorias.
  • 1999 - EcmaScript (European Computer Manufacturers Association)
  • 2007 - EcmaScript 4 - Abandonada
  • 2008 - EcmaScript 3.1 -> EcmaScript 5
  • Julho 2011 - Junho 2015 - EcmaScript 6 (Harmony) - Especificação congelada, em fase de validação

Ambiente de execução

Compatible table

ECMAScript 6 Tools

let (block scope)

  • ES5

    Global Scope, Function Scope

    var doWork = function(flag) {
      if (flag) {
        var x = 3;
      }
      return x;
    }

    flag = true, result = 3
    flag = false, result = undefined

  • ES6

    Block Scope

    var doWork = function(flag) {
      if (flag) {
        let x = 3;
      }
      return x;
    }

    flag = true or false, Reference error

let (block scope)

  • ES5

    Global Scope, Function Scope

    var doWork = function(flag) {
      var x;
      if (flag) {
        x = 3;
      }
      return x;
    }

    flag = true, result = 3
    flag = false, result = undefined

  • ES6

    Block Scope

    var doWork = function(flag) {
      if (flag) {
        let x = 3;
      }
      return x;
    }

    flag = true or false, Reference error

Destructuring

Destructuring

  • ES5

    function getPerson() {
      return {
        name: "John Lennon",
        age: 33,
        address: {
          city: "New York"
        }
      }
    }
    
    var person = getPerson();
    var personName = person.name;
    var personCity = person.address.city;
                  
  • ES6

    function getPerson() {
      return {
        name: "John Lennon",
        age: 33,
        address: {
          city: "New York"
        }
      }
    }
    
    let {
      name:personName,
      address:{city:personCity}
    } = getPerson();
                  

Destructuring

  • ES5

    var result = doStuff(
      "api/person", {
        data: "test",
        overwrite: false
      }
    );
    
    function doStuff(url, options) {
      //url
      //options.data
      //options.overwrite
    }
  • ES6

    var result = doStuff(
      "api/person", {
        data: "test",
        overwrite: false
      }
    );
    
    function doStuff(url, {data, overwrite}) {
      //url
      //data
      //overwrite
    }

Default Parameter Values

  • ES5

    var getName(name) {
      var name = name || "Francisco";
      return name;
    }
  • ES6

    var getName(name = "Francisco") {
      return name;
    }

Rest Parameters

  • ES5

    var sum = function() {
      var result = 0;
      for(var i = 0;
              i < arguments.length; i++) {
        result += arguments[i];
      }
      return result;
    }
    
    var result = sum(1,2,3);
  • ES6

    var sum = function(...numbers) {
      var result = 0;
      for(var i = 0;
              i < numbers.length; i++) {
        result += numbers[i];
      }
      return result;
    }
    
    var result = sum(1,2,3);

Spread Operator

  • ES6

    var sum3elements = function(x, y, z) {
      return x + y + z;
    }
    
    var myArray = [1,2,3];
    var result = sum3elements(...myArray);
  • ES6

    var a = [4,5,6];
    var b = [1,2,3,...a,7,8,9];
    //b = [1,2,3,4,5,6,7,8,9];

Template Literals
(Interpolation)

  • ES5

    var category = "music";
    var id = 123;
    var url = "http://myserver/" + category + "/" + id;
  • ES6

    let category = "music";
    var id = 123;
    var url = `http://myserver/${category}/${id}`;

Class

  • class Person {
      constructor(name, age) {
        this._name = name;
        this._age = age;
      }
      get name() {
        return this._name;
      }
      set name(value) {
        this._name = value;
      }
      getFullDescription() {
        return `${this._name}, ${this._age} years old`;
      }
    }
    
    let person = new Person("John", 25);
    person.name = "Paul";
    person.getFullDescription() // Paul, 25 years old
  • class Employee extends Person {
      constructor(title, name, age) {
        super(name, age);
        this._title = title;
      }
      get title() {
        return this._title;
      }
      getFullDescription() {
        return `${this._title} ${super()}`;
      }
    }
    
    let employee = new Employee("Mr.", "George", 39);
    employee.getFullDescription() //Mr. George, 39 years old

Arrow Functions

For of

  • ES5

    var numbers = [1,2,3,4];
    for (var index in numbers) {
      console.log(numbers[index]);
    }
    
  • ES6

    let numbers = [1,2,3,4];
    for (let number of numbers) {
      console.log(number);
    }

For of

  • High level

    let numbers = [1,2,3,4];
    let sum = 0;
    for (let n of numbers) {
      sum += n;
    }
    //sum = 10;
  • Low level

    let numbers = [1,2,3,4]; //Array
    let sum = 0;
    //Retrieving a iterator
    let iterator = numbers[Symbol.iterator]();
    let next = iterator.next();
    // { value: 1; done: false }
    while (!next.done) {
      sum += next.value;
      next = iterator.next();
    }
    //sum = 10;

Iterator implementation

  • let iterator = new RangeIterator(1,4);
    let next = iterator.next();
    // { value: 1; done: false }
    while (!next.done) {
      sum += next.value;
      next = iterator.next();
    }
    //sum = 10;
  • class RangeIterator {
      constructor(start, end) {
        this.current = start;
        this.end = end;
      }
      next() {
        let result = { value: undefined, done: true };
        if (this.current <= this.end) {
          result.value = this.current;
          result.done = false;
          this.current += 1;
        }
        return result;
      }
    }

Generators

  • High level

    let rangeIterator = function*(start, end) {
      for (let i = start; i<= end; i++) {
        yield i;
      }
    };
    
    let iterator = rangeIterator(1,4);
    let next = iterator.next();
    // { value: 1; done: false }
    let next = iterator.next();
    // { value: 2; done: false }
  • Low level

    class RangeIterator {
      constructor(start, end) {
        this.current = start;
        this.end = end;
      }
      next() {
        let result = { value: undefined, done: true };
        if (this.current <= this.end) {
          result.value = this.current;
          result.done = false;
          this.current += 1;
        }
        return result;
      }
    }

Comprehensions

  • Arrays
    Imperative vs Declarative

    let numbers = [];
    for (let n of [1,2,3]) {
      numbers.push(n * n);
    }
    //numbers = [1, 4, 9]
    let numbers = [for (n of [1, 2, 3]) n * n]
    //numbers = [1, 4, 9]
  • Iterator
    Imperative vs Declarative

    let numbers = function*() {
      for (let i = 1; i<= 3; i++) {
        yield i * i;
      }
    };
    let numbers = (for (n of [1, 2, 3]) n * n)
    //Array.from(numbers) = [1, 4, 9]

Custom Iterables

  • class Company {
      constructor() {
        this.employees = [];
      }
      addEmployees(...names) {
        this.employees = this.employees.concat(names);
      }
      *[Symbol.iterator]() {
        for (let e of this.employees) {
          yield e;
        }
      }
    }
    let filter = function*(items, predicate) {
      yield* (for (item of items) if (predicate(item)) item);
    }
  • let take = function*(items, number) {
      if (number < 1) return;
      var count = 0;
      for (let item of items) {
        yield item;
        count += 1;
        if (count >= number) {
          return;
        }
      }
    }
    
    let company = new Company();
    company.addEmployees("David", "Roger", "Richard", "Nick")
    let count = 0;
    for (let employee of take(filter(company, e => e[0] == 'R'),1)) {
      count += 1;
    }
    //count = 1;
    

Async - Callbacks (ES5)

  • function getCompanyFromOrderId(orderId) {
      try {
        getOrder(orderId, function(order) {
          try {
            getUser(order.userId, function(user) {
              try {
                getCompany(user.companyId, function(company) {
                  try { //do something with company }
                  catch (ex) { //handle exception }
                }
              } catch (ex) { //handle exception }
            });
          } catch (ex) { //handle exception }
        });
      } catch (ex) { //handle exception }
    }
  • Problemas:

    • Dificil de lidar com error handling;
    • Lidar com vários processos assincronos é dificil de gerenciar;
    • O callback tem multiplas responsabilidades:
      • Processar resultados da chamada assincrona
      • Precisa chamar outros processos baseado no resultado
        da chamada assincrona.

Async - Promises

  • function getCompanyFromOrderId(orderId) {
      getOrder(orderId).then(function(order) {
        return getUser(order.userId);
      }).then(function(user) {
        return getCompany(user.companyId);
      }).then(function(company) {
        //do something with company
      }).then(undefined, function(error) {
        //handle error
      })
    }
  • function getOrder(orderId) {
      return Promise.resolve({userId: 35});
    }
    
    function getUser(userId) {
      return Promise.resolve({companyId:38});
    }
    
    function getCompany(companyId) {
      return Promise.reject('Ooops!');
    }

Async - Promises

  • Promise.all

    let courseIds = [1,2,3];
    let promises = [];
    for (let id of courseIds) {
      promises.push(getCourse(id));
    }
    Promise.all(promises).then(function(values) {
      expect(values.length).toBe(3);
    });
  • Promise.race

    let courseIds = [1,2,3];
    let promises = [];
    for (let id of courseIds) {
      promises.push(getCourse(id));
    }
    Promise.race(promises).then(function(value) {
      expect(value.name).toBeDefined();
    });

Modules - IIFE module

(Immediately-Invoked Function Expression)
  • ES5

    (function(target) {
      var privateDoWork = function(name) {
        return name + " is working";
      };
      var Employee = function(name) {
        this.name = name;
      }
      Employee.prototype = {
        doWork: function() {
          return privateDoWork(this.name);
        }
      }
      target.Employee = Employee;
    }(window));
  • ES6

    es6/employee.js
    let s_name = Symbol();
    export class Employee {
      constructor(name) {
        this.[s_name] = name;
      }
      get name() {
        return this[s_name];
      }
    }
    module {Employee} from "es6/employee";
    var employee = new Employee("Gileno");
    employee.name = "Francisco"
    //employee.name = "Gileno";

Referências

http://www.pluralsight.com/courses/javascript-fundamentals-es6

http://en.wikipedia.org/wiki/ECMAScript

http://odetocode.com/blogs/all

Dados:

http://gileno.site44.com/ecmascript6/slides

Contato: francisco.gileno@cesar.org.br