The power of ECMAScript 6

Created by Charles King / @thebringking

Who am I?

Me

  • Husband and father of two
  • Software Engineer for ~nine years
  • Web stuff for ~three years
  • Work for Elegant Thought

ECMAScript

Scripting language standardized by Ecma International

Most popular implementation? JavaScript!

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+

Mostly new prototypes

2013

ES6 proposal freeze

August, 2014

ES6 feature freeze

Jan, 2015

Renamed to ES2015...?

~March, 2015

Offical ES6 pub process starting

Talk is cheap. Show me the code.- Linus Torvalds

let

JavaScript finally introduces a third scope, block scope

No more hoisting

let x = 31; if (true) { let x = 71; // different variable } console.log(x); // 31

const

Read only, named variables

Block scoped

const apiBase = "https://mysite.com/api/v1/"; const clientId = "Adxk38dn3c9u1ndk"; //block scoped if (true) { const apiBase = "https://othersite.com/api/v2/"; console.log(apiBase + clientId); //https://othersite.com/api/v2 } apiBase = "https://somewhereelse"; //Syntax error - apiBase is read-only console.log(apiBase+clientId); //https://mysite.com/api/v1/Adxk38dn3c9u1ndk

Arrow functions

A function shorthand or Lambda using the fat-arrow " => " syntax.

No constructor!

Not just syntax sugar. Arrow functions automatically bind "this" from the containing scope.

//array const items = [1, 2, 3, 4]; //expression bodies or lambda let byTwo = items.map(i => i * 2); //with a block let byFour = items.map(i => { return i * 4; }); //lexical this function Person() { this.name = "Charles"; this.nickNames = ["Charlie", "Chuck", "Chuckles"]; this.print = () => { return this.nickNames.map((n) => { return this.name + " is nicknamed " + n; }); }; } console.log(new Person().print()); //["Charles is nicknamed Charlie","Charles is nicknamed Chuck", //"Charles is nicknamed Chuckles"]

String templates

Allows for string literals with embedded expression interpolation.

Multi-line strings!

//define some classes const style = { width: "25px", height: "50px", display: "inline-block" } //arbitrary padding function function getPadding() { return 44; } //interpolate a literal string let tmpl = ` <div style="display:${style.display};padding:${getPadding()};"> <span style="width:${style.width};height:${style.height}"> Hi it's ${new Date()} </span> </div > `; //log our string literal console.log(tmpl);

Destructuring assignments

Destructure: To dismantle/destroy the structure of something

Object and Array destructuring

//works on arrays, or objects function getName(args) { if ( Array.isArray(args) ) { //assign the first and second element of the array let [firstName,lastName] = args; return `${firstName} ${lastName}`; } else { //assign the firstName key and lastName key let {firstName,lastName} = args; return `${firstName} ${lastName}`; } } console.log(getName(["Charlie", "King"])); //you can skip elements let items = [ 1,2,3,4,5 ]; //new hotness let [,second, third, fourth] = items; console.log([second,third,fourth]); //useful for selecting keys inside an expression let books = [ { name:"Javascript: The Good Parts", ISBN:1224283}, { name: "Effective Javascript", ISBN:128263}, { name: "The Principles of Object-Oriented JavaScript", ISBN:122663} ]; //old way let bookISBNS = books.map(function(b){ return b.ISBN; }); //new hotness let bookNames = books.map( ({name}) => name); console.log(bookISBNS); console.log(bookNames);

Object literals

New property value shortand syntax

let name = "Charlie", age = 29; const me = { name, age, //old way weight: function(){ return 86.1826; }, //new hotness height() { return 180; } } //view the results console.log(me.name); console.log(me.age); console.log(me.weight()); console.log(me.height());

Default args

Define default parameters for functions

Encloses the outer scope

//OMG default params function getApiUrl (resource, base = "http://b.com/api") { return `${base}/${resource}`; } let staticBase = "http://b.com/content"; //you can utilize outer scope function getStaticUrl (resource, base = staticBase) { return `${base}/${resource}`; } ////OMGWTF expressions in params!! 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));

Spread operator

Expands expressions where multiple args are expected

A better fn.apply()

function getFullName (firstName,lastName) { return `${firstName} ${lastName}`; } let names = ["Charles","King","James","King","Maggie","King"]; //spread array as args let fullName = getFullName(...names); console.log(fullName); //combine with destruturing let [ cFirst, cLast, ...rest ] = names; console.log([cFirst,cLast,rest]); //or array literal concatenation let who = ["Spongebob","Squarepants"] let where = [...who, "lives in", "a", "pineapple","under","the","sea"]; console.log(where); //use for push and unshift let start = [1,2,3]; let end = [4,5,6]; let more = [7,8,9]; end.unshift(...start); end.push(...more); //tada console.log(end);

Classes

A formal inheritance syntax comes to JavaScript

Really just syntactical sugar over JS prototypical inheritance

//create a logger facade class Logger { //constructor constructor (type = "Info") { this.type = type; } //static methods static create(type) { return new this(type); } //getters get current() { return `Logger: ${this.type}`; } //and setters set current(type) { this.type = type; } log (message) { let msg = `%c ${new Date().toISOString()}: ${message}`; switch (this.type) { case "Info": console.log(msg, 'background:#659cef;color:#fff;font-size:14px;' ); break; case "Error": console.log(msg, 'background: red; color: #fff;font-size:14px;' ); break; case "Debug": console.log(msg, 'background: #e67e22; color:#fff; font-size:14px;' ); break; default: console.log(msg); } } } //create an instance of our logger const debugLogger = new Logger("Debug"); debugLogger.log("Hello"); debugLogger.log(debugLogger.current); //extend it class ConfigurableLogger extends Logger { //getters get current() { return `ConfigurableLogger: ${this.type}`; } log (message, type) { this.type = type; super.log(message); } } //create instance of our configurable logger const cLogger = ConfigurableLogger.create("Debug"); cLogger.log("Configurable Logger", "Info"); cLogger.log(cLogger.current); cLogger.log(cLogger instanceof ConfigurableLogger); // true cLogger.log(cLogger instanceof Logger); // true

Iterators

"Iterable" protocol allows object to define their own iteration behavior

"Iterable" objects can be iterated over using 'for...of' loops

"Iterators" are objects that implement a next() method that returns {value,done:bool}

//obligatory fibonacci let fibonacci = { // notice the special Symbol.iterator key [Symbol.iterator]() { let pre = 0, cur = 1; return { next() { [pre, cur] = [cur, pre + cur]; return { done: false, value: cur } } } } } //Iterable can be iterated with for...of //ensure to break for infinite iterables for (var n of fibonacci) { if (n > 1000) break; console.log(n); }
//strings are iterable! const myName = "Charlie King"; //so are arrays, as you would expect let myHeight = ['5','11']; //grab the chars for ( let char of myName ) { console.log(char); } //grab the items in array for ( let item of myHeight ) { console.log(item); } //spread needs iterables console.log(`Spreading: ${[...myName]}`); console.log(`Spreading: ${[...myHeight]}`); //so does destructing let [c,h,a] = [...myName]; console.log(`Destructuring ${c} ${h} ${a}`); //you can also grab the iterator let stringIterator = myName[Symbol.iterator](); for ( let i=0; i < 3; i++ ) { console.log( stringIterator.next() ); }

Generators

Introduces functions that "yield" control flow

Seen in other languages like C#, Python

Looks like a function, however it returns an iterator object

//generator function* idMaker(idx) { var index = idx || 0; //infinite loop! while (true) { //get the value of next, and yield next index var reset = yield index++; //did they ask for a reset? if (reset) { index = idx || 0; } } } //create new generator iterator, notice no 'new' const gen = idMaker(); //grab some IDs //each next returns > { value: val, done: false } const ids = [gen.next(), gen.next(), gen.next(true)]; console.log(ids);
//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)); });

Modules

Standardized method for modularizing your JS code

Borrows concepts from Asynchronous Module Definition (AMD) and CommonJS Modules

Compact like CommonJS, async like AMD

Statically analyzed, so you can have circular deps

Modules

No more UMD!

                
(function(root, factory) {
    if (typeof define === 'function' && define.amd) {

        define(['b'], function(b) {
                    return (root.returnExportsGlobal = factory(b));
         });

    } else if (typeof exports === 'object') {

        module.exports = factory(require('b'));

    } else {

         root.returnExportsGlobal = factory(root.b);

    }
(this, function(b) {

    //finally do actual work
    return {};
}));
                
            
//------------------------task.js------------- export var falsy = 0; export let truthy = 1; export const read_only = "String"; export function spawn(){}; export function* enqueue(){}; export class Task {}; export default function () {}; //------------------------foo.js------------- //named default and others import taskjs, { spawn, enqueue, truthy, falsy, read_only, Task } from 'task'; //grab just the default export import taskjs from 'task'; //just named import { spawn, enqueue } from 'task'; //import and rename import { spawn as s, enqueue } from 'task'; //entire module as an object import * as task from 'task'; //load the module, don’t import anything import 'task';
//import config System.import('task') .then(task => { //do stuff with task }) .catch(error => { });

Promises

Promises are objects that represent an eventual result.

Lets asynchronous methods return values like synchronous methods

//simulate some async task function someLongTask() { return new Promise(function(resolve, reject) { setTimeout(function() { resolve("someLongTask"); }, 1000); }); } //simulate some other async task function someOtherLongTask(msg) { return new Promise(function(resolve,reject){ setTimeout(function(){ resolve("someOtherLongTask says: " +msg); },1500); }); } //run a task someLongTask() .then(function (msg) { console.log("Single: "+ msg); }); //run chained tasks someLongTask() .then(someOtherLongTask) .then(function (msg) { console.log("Chained: "+msg); }); //or wait for all of them var promises = [someLongTask(), someOtherLongTask("Hello")]; Promise.all(promises).then(function(results) { var msg1 = results[0]; var msg2 = results[1]; console.log("All: " + msg1+ " then "+ msg2); });

Map, Set, WeakMap, WeakSet

Map

Just a simple Key-Value pair

Except the key can be any value, not just primitives

Key equality is based on the "same-value" algorithm: NaN is considered the same as NaN (even though NaN !== NaN) and all other values are considered equal according to the semantics of the === operator. -MDN

var m = new Map(); m.set("hello", 42); //create an obj const Person = { name: "Charlie" } //add the complex key m.set(Person, "present"); //get the value m.get(Person) === "present"; //iterable for (var v of m.values()) { console.log("value:" +v); } for (var k of m.keys()) { console.log("key:" + JSON.stringify(k)); } //supports size, not length; console.log(m.size);

Set

Iterable object of unqiue values

Iterable in insertion order

No "set", just "add"

var s = new Set(); s.add("hello"); //create an obj const Person = { name: "Charlie" } //add the complex value s.add(Person); //get the value s.has(Person) === true; // try re-add the same value, ignored s.add(Person); //iterable for (var item of s) { console.log(item); } //supports size; console.log(s.size);

WeakMap

Like a Map, but not iterable

Keys cannot be primitive types. Keys are objects and are "weakly" held

//Weak, ya super weak. var wm = new WeakMap(); //create an obj const Person = { name: "Charlie" } wm.set(Person, "present"); //get the value console.log(wm.has(Person) === true);

WeakSet

Like a Set, but not iterable

Values cannot be primitive types. Values are objects and are "weakly" held

//weak set, bro var ws = new WeakSet(); //create an obj const Person = { name: "Charlie" } ws.add(Person); //get the value console.log(ws.has(Person) === true);

Features not-covered

  • Symbols
  • Proxies
  • Block level named functions (bad idea?)
  • Typed Arrays
  • Reflect
  • New prototype methods ( String, Array, Number, Object)
  • Tail call optimization (TCO)

Using ES6 Today

Browser support

Name Version Coverage
Tech preview 70%
37 (Nightly), 36 (Dev), 35 (Normal) 65%, 64%, 57%
42 (Chromium Dev), 41 (Chromium Beta), 40 (Chrome) 44%, 43%, 30%
8 (mobile and desktop) 20%

Source - kangax

Server support

Name Version Coverage
1.2.0 42%
0.12.0 25%

Source - kangax

Transpilers

Project Coverage Where
78% https://babeljs.io/
66% https://github.com/google/traceur-compiler
13% http://facebook.github.io/react/
TypeScript 9% http://www.typescriptlang.org/

Source - kangax

ES6 brings powerful new features to JS

JavaScript grown-up. More concise, less error-prone

You can use it today, and should!

Questions?