ECMAScript6 – ECMAScript



ECMAScript6 – ECMAScript

1 0


ecmascript6-presentation

Presentation: ECMAScript 6 Overview

On Github grime85 / ecmascript6-presentation

ECMAScript6

Overview of new features

ECMAScript

Scripting language standardized by ECMA International

Most popular implementation? JavaScript!

  • 1961
  • European Computer Manufacturers Association
  • 1994 - ECMA-> ECMA International
  • "Europejskie Stowarzyszenie Producentów Opakowań z Kartonu" (European Carton Makers Association)
  • JavaScript, ActionScript, JScript

1995

JS is born. Created by Brendon Eich

1997

ECMA-262 Ed 1. (ES1) Created by TC39 committee (Emca International)

1998

ES2

1999

ES3

IE 6-7-8, Firefox 1

2000

Work started on ES4

2003

ES4 totally abandoned

2005

Adobe, Mozilla and Google start work on ES4 again

2007

Microsoft, Yahoo, Google, and TC39 ratify ES3.1

Later became known as ES5

2008

Some ES4 proposals rolled into ES Harmony (ES6)

2009

ES5 spec finalized

2011

ES5 released

Implemented in JS Version 1.8.5

IE9+, Firefox 3.5+ era, Chrome 2.0+

2013

ES6 proposal freeze

August, 2014

ES6 feature freeze

Jan, 2015

Renamed to ES2015...?

March, 2015

Offical ES6 pub process starting

June 17, 2015

ECMAScript® 2015 Language Specification

Block scope

let and const

let

let x = 123; if (true) { let x = 456; } console.log(x);

const

  • Read only
  • Represents block scope
const PI = 3.141593; const subject = "Math"; //block scope if (true) { const PI = 3.14; console.log(PI + subject); } PI = 3.1415; // error console.log(PI + subject);

Arrow functions

  • fat-arrow syntax "=>"
  • No constructor!
  • lexical this
function Person() { this.name = "Rafal"; this.age = 20; this.interval = setInterval(() => { this.showPerson(); }, 1000); this.showPerson = () => { console.log(this.name + ", wiek: " + this.age); this.age === 35 ? this.stop() : this.age += 1; } this.stop = () => { clearInterval(this.interval); } } var person = new Person();

String templates

Nesting expression inside string

//es6: let a = { val: 234 }; let b = 2; let c = () => { return 345; } let sumES5 = `suma: ${a.val} + ${b} + ${c()} to: ${a.val + b + c()}`; console.log(sumES5); //es5: var d = { val: 234 }; var e = 2; var f = function() { return 345; } var sumES6 = "suma: " + d.val + " + " + e + " + " + f() + " to: " + (d.val + e + f()); console.log(sumES6);

Destructuring assignments

Allow to create pack of data

Pack can be created as an array: (array destructuring), or object (object destructuring)

Array destructuring

// ES5 var point = [3, 4]; var x = point[0]; var y = point[1]; console.log('es5 x: ' + x); console.log('es5 y: ' + y); // ES6 let newPoint = [1, 2]; let [newX, newY] = newPoint; console.log('es6 x: ' + newX); console.log('es6 y: ' + newY); // .. and reverse! [newX, newY] = [newY, newX]; console.log([newX, newY]);
// omitting values let arr = [1, 2, 3]; let [a, , c] = arr; console.log(a); console.log(c); //nested values let nested = [1, [2, 3], 4]; let [d, [e], f] = nested; console.log(d); console.log(e); console.log(f);

Object destructuring

let point = { x: 1, y: 2 }; let { x: a, y: b } = point; console.log(a); console.log(b);
// nested objects let point = { x: 1, y: 2, z: { one: 3, two: 4 } }; let { x: a, y: b, z: { one: c, two: d } } = point; console.log(a); console.log(b); console.log(c); console.log(d);

Mixed destructuring

function mixed () { return { one: 1, two: 2, values: [3, 4, 5] }; } let { one: a, two: b, values: [c, , e] } = mixed(); console.log(a); // 1 console.log(b); // 2 console.log(c); // 3 console.log(e); // 5

Default parameters

let getApiUrl = (resource, base = "http://example.com/") => { return `${base}/${resource}`; } let staticBase = "http://example.pl/static"; let getStaticUrl = (resource, base = staticBase) => { return `${base}/${resource}`; } function getThumb(resource, width, dpi = width/10 ) { return `${staticBase}/${resource}?width=${width}&dpi=${dpi}`; } console.log(getApiUrl("image")); console.log(getStaticUrl("doc.pdf")); console.log(getThumb("image.jpg",200));

Object literals

let name = "Rafal", age = 29; const me = { name: name, age, // new way weight: function(){ return 86.1826; }, //new way height() { return 180; } } console.log(me.name); console.log(me.age); console.log(me.weight()); console.log(me.height());

Rest parameters

allow passing the parameters to functions using three dots.

//ES5 function sum() { var numbers = Array.prototype.slice.call(arguments); var result = 0; numbers.forEach(function (number) { result += number; }); return result; } console.log(sum(1)); // 1 console.log(sum(1, 2, 3, 4, 5)); // 15
//ES6 function sum(...numbers) { var result = 0; numbers.forEach(function (number) { result += number; }); return result; } console.log(sum(1)); // 1 console.log(sum(1, 2, 3, 4, 5)); // 15

Spread operator

// ES5 function sum(a, b, c) { return a + b + c; } var args = [1, 2, 7]; console.log(sum.apply(sum, args));
// ES6 function sum(a, b, c) { return a + b + c; } var args = [1, 2]; console.log(sum(...args, 3));
// ES5 let values = [25, 50, 75, 100] console.log(Math.max.apply(Math, values)); // ES6 console.log(Math.max(...values));

Classes

//ES5 function Vehicle (name, type) { this.name = name; this.type = type; }; Vehicle.prototype.getName = function getName(){ console.log(this.name); }; Vehicle.prototype.getType = function getName(){ console.log(this.type); }; var car = new Vehicle('Audi', 'samochód'); car.getName(); car.getType();
//ES6: class, constructor class Vehicle { constructor (name, type) { this.name = name; this.type = type; } getName () { console.log(this.name); } getType() { console.log(this.type); } }; let car = new Vehicle('Audi', 'samochód'); car.getName(); car.getType();

Classes

Inheritance

//ES5 function Vehicle (name, type) { this.name = name; this.type = type; }; Vehicle.prototype.getName = function getName(){ console.log(this.name); return this.name; }; Vehicle.prototype.getType = function getName(){ console.log(this.type); return this.type; }; function Car (name) { Vehicle.call(this, name, 'car'); } Car.prototype = Object.create(Vehicle.prototype); Car.prototype.constructor = Car; Car.parent = Vehicle.prototype; Car.prototype.getName = function () { console.log('Oto mój pojazd: '+ this.name); }; var car = new Car('audi'); console.log(car.getName()); console.log(car.getType());
//ES6 //super - calling function from parent class Vehicle { constructor (name, type) { this.name = name; this.type = type; } getName() { console.log(this.name); return this.name; } getType() { console.log(this.type); return this.type; } }; class Car extends Vehicle { constructor (name) { super (name, 'car'); } getName() { return 'Oto samochód: ' + super.getName(); } } let car = new Car('audi'); console.log(car.getName()); console.log(car.getType());

Classes

Static functions

//ES6 //connected with constructor(class), not with an object(prototype) class Vehicle { constructor (name, type) { this.name = name; this.type = type; } getName() { console.log(this.name); return this.name; } getType() { return this.type; } static create (name, type) { return new Vehicle(name, type); } }; let car = Vehicle.create('Audi', 'car'); car.getName();

Classes

getters setters

//Getters, setters in ES6 class Car { constructor (name, type) { this._name = name; } set name (name) { this._name = name; console.log('setter: ' + this._name); } get name () { console.log('getter: '+ this._name); return this._name; } }; let car = new Car ('Audi'); car.name; car.name = 'BMW'; car.name;

Map, Set, WeakMap, WeakSet

Map

Maps are a store for key / value pairs. Key and value could be a primitives or object references.

var myMap = new Map(); var keyObj = {}, keyFunc = function () {}, keyString = "a string"; // setting the values myMap.set(keyString, "value associated with 'a string'"); myMap.set(keyObj, "value associated with keyObj"); myMap.set(keyFunc, "value associated with keyFunc"); myMap.size; // 3 // getting the values myMap.get(keyString); // "value associated with 'a string'" myMap.get(keyObj); // "value associated with keyObj" myMap.get(keyFunc); // "value associated with keyFunc" myMap.get("a string"); // "value associated with 'a string'" // because keyString === 'a string' myMap.get({}); // undefined, because keyObj !== {} myMap.get(function() {}); for (let item of myMap) console.log(item);

WeakMap

Like a Map, but not iterable

Keys cannot be primitive types. Keys are objects and are "weakly" held (If there is no other reference to an object stored in the WeakMap, they can be garbage collected)

var wm1 = new WeakMap(), wm2 = new WeakMap(), wm3 = new WeakMap(); var o1 = {}, o2 = function(){}, o3 = window; wm1.set(o1, 37); wm1.set(o2, "azerty"); wm2.set(o1, o2); // a value can be anything, including an object or a function wm2.set(o3, undefined); wm2.set(wm1, wm2); // keys and values can be any objects. Even WeakMaps! wm1.get(o2); // "azerty" wm2.get(o2); // undefined, because there is no value for o2 on wm2 wm2.get(o3); // undefined, because that is the set value wm1.has(o2); // true wm2.has(o2); // false wm2.has(o3); // true (even if the value itself is 'undefined') wm3.set(o1, 37); wm3.get(o1); // 37 wm1.has(o1); // true wm1.delete(o1); wm1.has(o1); // false

WeakMap

Using Weakmaps we can actually create private variables not accessible from outside of the class and only internally.

WeakMaps are always garbage collected when the instance is destroyed, so memory leaks are never an issue like they are when using an array.

// Define as constant const privateData = new WeakMap(); class MyClass { constructor(name, age) { privateData.set(this, { name: name, age: age }); } getName() { return privateData.get(this).name; } getAge() { return privateData.get(this).age; } } let p = new MyClass('Rafal', 26); console.log(p.getAge());

Set

The Set object lets you store unique values of any type, whether primitive values or object references.

var mySet = new Set(); mySet.add(1); mySet.add(5); mySet.add("some text"); mySet.has(1); // true mySet.has(3); // false, 3 has not been added to the set mySet.has(5); // true mySet.has(Math.sqrt(25)); // true mySet.has("Some Text".toLowerCase()); // true mySet.size; // 3 mySet.delete(5); // removes 5 from the set mySet.has(5); // false, 5 has been removed mySet.size; // 2, we just removed one value

WeakSet

WeakSet objects are collections of objects.

Like a Set, but not iterable

An object in the WeakSet may only occur once; it is unique in the WeakSet's collection.

Values cannot be primitive types. Values are objects and are "weakly" held (If there is no other reference to an object stored in the WeakSet, they can be garbage collected)

var ws = new WeakSet(); var obj = {}; var foo = {}; ws.add(window); ws.add(obj); ws.has(window); // true ws.has(foo); // false, foo has not been added to the set ws.delete(window); // removes window from the set ws.has(window); // false, window has been removed ws.clear(); // empty the whole WeakSet

Iterators

Iterator & iterable

iterator - an object with a next method that returns { done, value } tuples.

iterable - an object which has Symbol.iterator method inside.

Build-in iterables:

  • String
  • Array
  • Map
  • Set
let arr = ['a', 'b', 'c']; let iter = arr[Symbol.iterator](); console.log(iter.next()); console.log(iter.next()); console.log(iter.next()); console.log(iter.next());
// Iterator w ES5 function createIterator(items) { var i = 0; return { next: function() { var done = (i >= items.length); var value = !done ? items[i++] : undefined; return { done: done, value: value }; } }; } var iterator = createIterator([1, 2, 3]); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); // kazdy kolejny call console.log(iterator.next());
// Random iterator let random1_10 = (items = 1) => { return { [Symbol.iterator]() { let cur = 0; return { next() { let done = cur === items, random = Math.floor(Math.random() * 10) + 1; ++cur; return { done: done, value: random } } } } }; }; for (let n of random1_10(5)) { console.log(n); }

Loops and iteratoion

Loops and iteratoion

for of loop

// array for (let x of ['a', 'b']) { console.log(x); } // strings for (let x of 'RAFAL') { console.log(x); } // map let map = new Map().set('a', 1).set('b', 2); for (let pair of map) { console.log(pair); } // set let set = new Set().add('a').add('b'); for (let x of set) { console.log(x); }

Loops and iteratoion

All major ES6 data structures (Arrays, Typed Arrays, Maps, Sets) have three methods that return iterable objects:

  • entries()
  • keys()
  • values()
// entries let arr = ['a', 'b', 'c']; for (let entry of arr.entries()) { console.log(entry); } // keys for (let key of arr.keys()) { console.log(key); } // values for (let value of arr.values()) { console.log(value); }

Generators

  • subtypes of iterators
  • use function* and yield
  • borrowed from Python language
// Simple generator function* generator () { yield 1; // pause yield 2; // pause yield 3; // pause yield 'done?'; // done } let gen = generator(); console.log(gen.next()); console.log(gen.next()); console.log(gen.next()); console.log(gen.next()); console.log(gen.next()); console.log(gen.next()); for (let val of generator()) { console.log(val); }
// Simple random1_10 generator, ES5 function random1_10 () { return { next: function() { return { value: Math.floor(Math.random() * 10) + 1, done: false }; } }; } let rand = random1_10(); console.log(rand.next());
// Simple random1_10 generator, ES6 function* random1_10 () { while (true) { yield Math.floor(Math.random() * 10) + 1; } } let rand = random1_10(); console.log(rand.next());

Mixing generators together (yield*)

function* random (max) { yield Math.floor(Math.random() * max) + 1; } function* random1_20 () { while (true) { yield* random(20); } } let rand = random1_20(); console.log(rand.next());

Different ways of implementation

Generator function expressions

let createIterator = function *(items) { for (let i=0; i < items.length; i++) { yield items[i]; } }; let iterator = createIterator([1, 2, 3]); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); // for all further calls console.log(iterator.next());

Generator object methods

// ES5 style var o = { createIterator: function *(items) { for (let i=0; i < items.length; i++) { yield items[i]; } } }; let iterator = o.createIterator([1, 2, 3]);
// ES6 style let o = { *createIterator(items) { for (let i=0; i < items.length; i++) { yield items[i]; } } }; let iterator = o.createIterator([1, 2, 3]);

Generator Class Methods

class MyClass { *createIterator(items) { for (let i=0; i < items.length; i++) { yield items[i]; } } } let o = new MyClass(); let iterator = o.createIterator([1, 2, 3]);

second use of next()

function* ticketGenerator() { for(var i = 0; true; i++) { yield i; } } let takeANumber = ticketGenerator(); console.log(takeANumber.next().value);
function* ticketGenerator() { for (var i = 0; true; i++) { var reset = yield i; if (reset) { i = -1; } } } let takeANumber = ticketGenerator(); console.log(takeANumber.next().value); console.log(takeANumber.next().value); console.log(takeANumber.next(true).value); console.log(takeANumber.next().value);

No more Callback HELL!

//advanced example from - http://modernweb.com/2014/02/10/replacing-callbacks-with-es6-generators/ //create an async function function delay(time, callback) { setTimeout(function() { callback("Slept for " + time); }, time); } //create a wrapper around a callback based function, to have it call next() function run(generatorFunction) { //grab the iterator, and pass in the callback var generatorItr = generatorFunction(resume); function resume(callbackValue) { //when the callback is called, call next, and pass the value generatorItr.next(callbackValue); } //start the iterator generatorItr.next() } //wrap our generator in the run method run(function* myDelayedMessages(resume) { console.log(yield delay(1000, resume)); console.log(yield delay(1200, resume)); });
ECMAScript6 Overview of new features