ECMAScript 6

@MichalZalecki

michalzalecki.com

Overview 

  • ECMAScript 1 - June 1997
  • ECMAScript 2 - June 1998
  • ECMAScript 3 - December 1999
  • ECMAScript 4 - Abandoned
  • ECMAScript 5 - December 2009
  • ECMAScript 5.1 - June 2011
  • ECMAScript 6 "Harmony" - June 2015
  • ECMAScript 7 - ?

LET

if (true) {
    var x = 1;
}
expect(x).toEqual(1);
if (true) {
    let x = 1;
}
expect(x).toEqual(1); // ReferenceError

LET

let funcs = [];
for (var i of [4, 5, 6]) {
    funcs.push(function() { return i; });
}
funcs[0](); // 6
funcs[1](); // 6
funcs[2](); // 6
let funcs = [];
for (let i of [4, 5, 6]) {
    funcs.push(function() { return i; });
}
funcs[0](); // 4
funcs[1](); // 5
funcs[2](); // 6

CONST

const x = 1;
const y = {x: 1};

x = 2;   // x is read-only
y.x = 2; // 2

Arrow functions

let square = x => x * x;

let triangleHeron = (a, b, c) => {
    let p = (a + b + c)/2;
    return Math.sqrt(p*(p-a)*(p-b)*(p-c));
};

let objectify = x => ({ value: x });

square(13); // 169
triangleHeron(3, 4, 5); // 6
objectify("foo"); // { value:"foo" }

Default Parameters

function f(list, indexA, indexB) {
    indexA = indexA || 0;
    indexB = indexB || list.length;
    return [list, indexA, indexB];
}

f([1, 2, 3]); // [[1, 2, 3], 0, 3]
f([1, 2, 3], 1); // [[1, 2, 3], 1, 3]
f([1, 2, 3], 1, 2); // [[1, 2, 3], 1, 2]
function f(list, indexA = 0, indexB = list.length) {
    return [list, indexA, indexB];
}
 
f([1, 2, 3]); // [[1, 2, 3], 0, 3]
f([1, 2, 3], 1); // [[1, 2, 3], 1, 3]
f([1, 2, 3], 1, 2); // [[1, 2, 3], 1, 2]

CLASSES

function Point(x, y) {
    this.x = x || 0;
    this.y = y || 0;
}

Point.prototype.distance = function(x, y) {
    return Math.sqrt(Math.pow(this.x - x, 2)
                   + Math.pow(this.y - y, 2));
};


var a = new Point(2, 1);
a.distance(1, 2); // 1.4142135623730951
class Point {
    constructor(x = 0, y = 0) {
        this.x = x;
        this.y = y;
    }
    distance(x, y) {
        return Math.sqrt(Math.pow(this.x - x, 2)
                       + Math.pow(this.y - y, 2));
    }
}

let a = new Point(2, 1);
a.distance(1, 2); // 1.4142135623730951

CLASSES

function Circle(r, x, y) {
    Point.call(this, x, y);
    this.r = r;
}
        
Circle.prototype = new Point();

var a = new Circle(6, 2, 1);
expect(a.r).toEqual(6);
class Circle extends Point {
    constructor(r, x, y) {
        super(x, y);
        this.r = r;
    } 
} 

let a = new Circle(6, 2, 1);
expect(a.r).toEqual(6);

Destructing Assignment

let [a, , [b, c]] = [1, 2, [3, 4]];

expect(a).toEqual(1);
expect(b).toEqual(3);
expect(c).toEqual(4);

Destructing Assignment

let {firstName, lastName: surname, 
     info: {age, driver}} =
    {firstName: "Foo", lastName: "Bar",
     info: {age: 20, driver: true}};
 
expect(firstName).toEqual("Foo");
expect(surname).toEqual("Bar");
expect(age).toEqual(20);
expect(driver).toEqual(true);

Rest Parameters

function buy(where, ...items) {
    return "I'm going to " + where + " to buy "
        + items.length + " items: "
        + items.slice(0, -1).join(", ")
        + " and " + items.slice(-1) + ".";
}
 
buy("the mall", "jacket", "bag", "headphones")
    // "I'm going to the mall to buy 3
    // items: jacket, bag and headphones."

Spread

function send(what, where, toWhom) {
    return "I'm sending " + what + " to " + toWhom
         + " who is in " + where + ".";
}
 
send(...["the letter", "Poland", "Mike"]);
    // "I'm sending the letter to Mike
    // who is in Poland."

Enhanced Object Literals

function greet(name) {
    return "Hello " + name;
}
let x = 2;
let obj = {
    [x*2]: "Computed Property Name",
    __proto__: {
        hi: function () { return "Hi!" },
        by: function () { return "By!" }
    },
    greet
};
 
expect(obj[4]).toEqual("Computed Property Name");
expect(obj.hi()).toEqual("Hi!");
expect(obj.by()).toEqual("By!");
expect(obj.greet("Bob")).toEqual("Hello Bob");

Symbols

expect(Symbol("bar"))
    .not.toBe(Symbol("bar"));

expect(Symbol.for("bar"))
    .toBe(Symbol.for("bar"));

Symbols

function Safe(secretData) {
    let s = Symbol("secret symbol");
    this[s] = secretData;
}

let obj = new Safe("secret");

expect(obj["secret symbol"]).toBeUndefined();
expect(obj[Symbol("secret symbol")])
    .toBeUndefined();
expect(obj[Object.getOwnPropertySymbols(obj)[0]])
    .toEqual("secret");

Iterators & for...oF

function fibonacci(i) {
    return {
        [Symbol.iterator]() {
            let pre = -1, cur = 1;
            return {
                next() {
                    [pre, cur] = [cur, pre + cur];
                    return {done: !(i--), value: cur};}
            }
        }
    }   
}
 
let fib = [];
for (let n of fibonacci(10)) {
    fib.push(n);
}
expect(fib).toEqual([0, 1, 1, 2, 3, 5, 8, 13, 21, 34]);

GENERATORS

function* foo() {
    let i = 0;
    yield ++i;
    yield ++i;
    yield ++i;
}
 
let seq = foo();
expect(seq.next().value).toEqual(1);
expect(seq.next().value).toEqual(2);
expect(seq.next().value).toEqual(3);

GENERATORS

function* flatten(t, n = 0) {
    if (t[n]) {
        if (Array.isArray(t[n]))
            yield* flatten(t[n])
        else
            yield t[n];
        yield* flatten(t, n + 1);
    }
}
 
let nums = [];
for (let n of flatten([10, 11, 12, [13, 14, [15, 16]], 17])) {
    nums.push(n);
}
expect(nums).toEqual([10, 11, 12, 13, 14, 15, 16, 17]);

GENERATORS

// The idea comes from
// http://youtu.be/s-BwEk-Y4kg?t=14m42s

function* powGenerator() {
    return Math.pow(yield "a", yield "b");
}
 
let g = powGenerator();
expect(g.next().value).toEqual("a");
expect(g.next(10).value).toEqual("b");
expect(g.next(2).value).toEqual(100);

Numeric Literals

expect([
    0b111,
    0b11110000,
    0b00001111
]).toEqual([
    7,
    240,
    15
]);
expect([
    0o7,
    0o360,
    0o17
]).toEqual([
    7,
    240,
    15
]);

Template literals

let name = "Foo";
let surname = "Bar";
 
expect(`${name} ${surname}`)
    .toEqual("Foo Bar");

Template literals

let name = "Michal";
let surname = "Zalecki";

`${name} ${surname} greats`
    // 'Michal Zalecki greats'

Email`${name} ${surname} greats`
    // 'Michal Zalecki <michal@michalzalecki.com> greats'
function Email(strs, ...values) {
    return values[0] + " " + values[1]
         + " <" + values[0].toLowerCase() + "@"
         + values[0].toLowerCase() + values[1].toLowerCase()
         + ".com>" + strs[strs.length - 1];
}

Promises

new Promise((resolve, reject) => {
    setTimeout(() => {
        if (!(-1/0)) {
            resolve("Success!");
        } else {
            reject(new Error("WTF?"));
        }
    }, 1000);
});
(new Promise(...))
    .then((data) => {
        expect(data).toEqual("Success!");
    })
    .catch((err) => {
        expect(err).toEqual(new Error("WTF?"));
    });

Promises

stepPromise(stepper.step())
    .then((stepper) => stepPromise(stepper.step()))
    .then((stepper) => stepPromise(stepper.step(2)))
    .then((stepper) => stepPromise(stepper.step()))
    .then((stepper) => stepPromise(stepper.step(3)))
    .then((stepper) => stepPromise(stepper.step(99999)))
    .then((stepper) => {}, (err) => {
        expect(err).toEqual(new Error("That's enough!"));
    });

Modules

// modules/math.js
export function sum(x, y) {
    return x + y;
}
export var pi = 3.141593;
 
// modules/person.js
export var name     = "Foo";
export var surname  = "Bar";
 
// modules.js
import * as mathematics from "modules/math";
import {name, surname} from "modules/person";

expect(mathematics.sum(2, 3)).toEqual(5);
expect(mathematics.pi).toEqual(3.141593);
 
expect(name).toEqual("Foo");
expect(surname).toEqual("Bar");

Modules

<script>
    System.import('modules/math').then((m) => {
        expect("2π = " + m.sum(m.pi, m.pi))
            .toEqual("2π = 6.283186");
    });
    System.import('modules/person').then((m) => {
        expect("I'm " + m.name + " " + m.surname)
            .toEqual("I'm Foo Bar");
    });
</script>

PROXY

var address = {
    'Marie Lynch': 'mlynch2@state.tx.us',
    ...
    'Ryan Bradley': 'rbradley3@com.com' };

var handler = {
    set: (target, property, value, receiver) => {
        if (!value.match(/^\S+@\S+\.\S+$/))
            throw new TypeError(`${value} is invalid email!`);
        target[property] = value;
        return true;
    },
    get: (target, property, receiver) => {
        return property in target ?
                   target[property] : "Not Found"; }
    // deleteProperty
    // enumerate
    // ...
};
var addressBook = new Proxy(address, handler);

try {
    addressBook['Joseph Fields'] = 'jfields9@fedbur.com';
    addressBook['Kathryn Lewis'] = 'klewis.com';
} catch(e) {
    console.error(e.message);
    // "klewis.com is invalid email!"
} 
console.log(addressBook['Marie Lynch']);
// "mlynch2@state.tx.us"

console.log(addressBook['Joseph Fields']);
// "jfields9@fedbur.com"

console.log(addressBook['Kathryn Lewis']);
// "Not Found"

What else?

  • Reflect
  • Object API
  • Number API
  • Math API
  • Array API
  • Map, Set, WeakMap, WeakSet
  • Tail Call Optimization
  • Typed Arrays
  • and more... (but not much more)

ES6 Features Runtime

git clone https://github.com/MichalZalecki/es6features-runtime

ECMAScript 6 Overview

http://michalzalecki.com/ecmascript-6-overview/

Questions?