You are on page 1of 90

The road to ES6, and beyond

A tale about JavaScripts past, present and future


Tom Van Cutsem
jsconf.be 2015

@tvcutsem
My involvement in JavaScript

2004-2008: built up expertise in


programming languages research during
my PhD

2010: Visiting Faculty at Google, joined


Caja team

Joined ECMA TC39 (Javascript


standardization committee)

Actively contributed to the ECMAScript 6


specification
Talk Outline

Part I: JavaScripts past, and the long road to ECMAScript 6

Part II: a brief tour of ECMAScript 6

Part III: using ECMAScript 6 today, and what lies beyond

Wrap-up
Part I
JavaScripts past, and the long road to ECMAScript 6
JavaScripts origins

Invented by Brendan Eich in 1995, then an intern at Netscape, to


support client-side scripting in Netscape navigator

First called LiveScript, then JavaScript, then standardized as


ECMAScript

Microsoft copied JavaScript in IE JScript, warts and all

Brendan Eich,
Inventor of JavaScript
The worlds most misunderstood language

Douglas Crockford,
Inventor of JSON
See also: JavaScript: The World's Most Misunderstood Programming Language
by Doug Crockford at http://www.crockford.com/javascript/javascript.html
The Good Parts

Functions as first-class objects

Dynamic objects with prototypal


inheritance

Object literals

Array literals
The Bad Parts

Global variables (no modules)

Var hoisting (no block scope)

with statement

Implicit type coercion


ECMAScript: Standard JavaScript

Carakan

Chakra Spidermonkey

V8 JavaScriptCore
ECMAScript: Standard JavaScript

Carakan

Chakra Spidermonkey

V8 JavaScriptCore
TC39: the JavaScript standardisation committee

Representatives from major Internet companies, browser vendors, web


organisations, popular JS libraries and academia

Maintains the ECMA-262 specification.

The spec is a handbook mainly intended for language implementors.


Extremely detailed to reduce incompatibilities.

ECMA-262
5th Edition / December 2009

ECMAScript Language
Specification

Allen Wirfs-Brock, Reference number


ECMA-123:2009

ECMA-262 technical editor


Ecma International 2009
ECMAScript specification: history

1st ed. 1997

2nd ed. 1998

3rd ed. 1999


ECMA-262
5th Edition / December 2009

ECMAScript Language
Specification

4th ed.

5th ed. 2009

6th ed. June 2015

Reference number
ECMA-123:2009

Ecma International 2009


TC39

Meets bi-monthly, mostly in the SF bay area. Meetings are technical,


not political in nature

Discussions held in the open on es-discuss@mozilla.org

Committee very much aware of the dangers of design-by-committee.

Champion model to combat this (each feature led by handful of experts)

Important decisions made by global consensus


esdiscuss.org is your friend
ECMAScript 5

1st ed. 1997

2nd ed. 1998

3rd ed. 1999


ECMA-262
5th Edition / December 2009

ECMAScript Language
Specification

4th ed.

5th ed. 2009

6th ed. June 2015

Reference number
ECMA-123:2009

Ecma International 2009


Ecmascript 5 Strict mode

How many of you have heard of ECMAScript 5 strict mode?

How many of you are writing all of their code in strict mode?
Ecmascript 5 Strict mode

Safer, more robust, subset of the language

Why? Among others:

No silent errors

True static scoping rules

Enabler for the larger ECMAScript 6 eort


Ecmascript 5 Strict mode

Explicit opt-in to avoid backwards compatibility constraints

How to opt-in
<script>
"use strict";
Per program (file, script tag, ...)
...
</script>
Per function

Strict and non-strict mode code can


interact (e.g. on the same web page) function f() {
"use strict";
...
}
Static scoping in ES5

ECMAScript 5 non-strict is not statically scoped

Four violations:

with (obj) { x } statement

delete x; // may delete a statically visible var

eval('var x = 8'); // may add a statically visible var

Assigning to a non-existent variable creates a new global variable


function f() { var xfoo; xFoo = 1; }
Ecmascript 5 Strict: syntactic restrictions

The following are forbidden in strict mode (signaled as syntax errors):

delete x; // deleting a variable


with (expr) {
...x...
} if (a < b) {
// declaring functions in blocks
function f(){}
{ a: 1, }
b: 2,
b: 3 } // duplicate property
var n = 023; // octal literal

function f(a,b,b) { function f(eval) {


// repeated param name // eval as variable name
} }
Ecmascript 5 Strict

Runtime changes (fail silently outside of strict mode, throw an


exception in strict mode)

function f() {
"use strict";
var xfoo;
xFoo = 1; // error: assigning to an undeclared variable
}

"use strict";
var p = Object.freeze({x:0,y:0});
delete p.x; // error: deleting a property from a frozen object
Part II
A brief tour of ECMAScript 6
ECMAScript specification

1st ed. 1997

2nd ed. 1998

3rd ed. 1999


ECMA-262
5th Edition / December 2009

ECMAScript Language
Specification

4th ed.

5th ed. 2009

6th ed. June 2015

Reference number
ECMA-123:2009

Ecma International 2009


ECMAScript 6

Major update: many new features (too many to list here)

Point-in-case: ES6 draft


rev 37 (april 2015)
ES5.1
ECMA-262
5th Edition / December 2009
ECMA-262
5th Edition / December 2009

ECMAScript Language
Specification ECMAScript Language
Specification

x 2.4
Reference number
ECMA-123:2009

Ecma International 2009

Reference number
ECMA-123:2009

Ecma International 2009

258-page pdf 613-page pdf


ECMAScript 6

Major update: many new features (too many to list here)

Recommended reading: Luke Hobans overview at

git.io/es6features

Luke Hoban,
Microsoft representative on TC39
ECMAScript 6

I will focus on the following loose themes:

Improving functions

Improving modularity

Improving control flow

Improving collections

Improving reflection (time permitting)


ECMAScript 6: improving functions

Arrow functions

Rest arguments

Optional arguments

Destructuring

Improved function scoping: let + const

Tail calls
ECMAScript 6: arrow functions

Shorter, and also automatically captures current value of this


No more var that = this;

function sum(array) {
return array.reduce(
ES5 function(x, y) { return x + y; }, 0);
}

function sum(array) {
ES6 return array.reduce((x, y) => x + y, 0);
}
ECMAScript 6: arrow functions

Shorter, and also automatically captures current value of this


No more var that = this;

function sum(array) {
return array.reduce(
ES5 function(x, y) { return x + y; }, 0);
}

function sum(array) {
ES6 return array.reduce((x, y) => x + y, 0);
}
ECMAScript 6: arrow functions

By default, body of an arrow function parsed as an expression

If you want to write a statement, use curlies:

function sumPositive(array) {
let sum = 0;
array.forEach(x => {
if (x > 0) { sum += x; }
});
return sum;
}

If you want to return an object, wrap parens around the curlies:

angles.map((a) => ({ cos: Math.cos(a), sin: Math.sin(a) }))


ECMAScript 6: arrow functions

By default, body of an arrow function parsed as an expression

If you want to write a statement, use curlies:

function sumPositive(array) {
let sum = 0;
array.forEach(x => {
if (x > 0) { sum += x; }
});
return sum;
}

If you want to return an object, wrap parens around the curlies:

angles.map((a) => ({ cos: Math.cos(a), sin: Math.sin(a) }))


ECMAScript 6: rest arguments

function printf(format) {
ES5 var rest = Array.prototype.slice.call(arguments,1);

}

function printf(format, ...rest) {


ES6
}
ECMAScript 6: rest arguments

function printf(format) {
ES5 var rest = Array.prototype.slice.call(arguments,1);

}

function printf(format, ...rest) {


ES6
}
ECMAScript 6: optional arguments

function greet(arg) {
ES5 var name = arg || world;
return Hello, + name;
}

function greet(name = world) {


ES6 return Hello, + name;
}
ECMAScript 6: optional arguments

function greet(arg) {
ES5 var name = arg || world;
return Hello, + name;
}

function greet(name = world) {


ES6 return Hello, + name;
}
ECMAScript 6: destructuring

// div(a,b) = q,r <=> a = q*b + r


function div(a, b) {
var quotient = Math.floor(a / b);
var remainder = a % b;
return [quotient, remainder];
}

ES5 ES6

var result = div(4, 3); var [q,r] = div(4, 3);


var q = result[0];
var r = result[1];
ECMAScript 6: destructuring

// div(a,b) = q,r <=> a = q*b + r


function div(a, b) {
var quotient = Math.floor(a / b);
var remainder = a % b;
return [quotient, remainder];
}

ES5 ES6

var result = div(4, 3); var [q,r] = div(4, 3);


var q = result[0];
var r = result[1];
ECMAScript 6: destructuring

Not just arrays, also for objects:

var node = binaryTree.findNode(key);


ES5 var left = (node !== undefined ? node.left : node);
var right = (node !== undefined ? node.right : node);

ES6 var { left, right } = binaryTree.findNode(key);


ECMAScript 6: destructuring

Not just arrays, also for objects:

var node = binaryTree.findNode(key);


ES5 var left = (node !== undefined ? node.left : node);
var right = (node !== undefined ? node.right : node);

ES6 var { left, right } = binaryTree.findNode(key);


ECMAScript 6: destructuring

Can do destructuring in parameter position. This gives us elegant


keyword parameters!
function fetchRows(options) {
var args = (options === undefined ? {} : options);
var limit = (args.limit === undefined ? 10 : args.limit);
ES5 var offset = (args.offset === undefined ? 0 : args.offset);
var orderBy = (args.orderBy === undefined ? id : args.orderBy);
console.log(limit, offset, orderBy);
});

function fetchRows({ limit=10, offset=0, orderBy=id}) {


ES6 console.log(limit, offset, orderBy);
});
ECMAScript 6: destructuring

Can do destructuring in parameter position. This gives us elegant


keyword parameters!
function fetchRows(options) {
var args = (options === undefined ? {} : options);
var limit = (args.limit === undefined ? 10 : args.limit);
ES5 var offset = (args.offset === undefined ? 0 : args.offset);
var orderBy = (args.orderBy === undefined ? id : args.orderBy);
console.log(limit, offset, orderBy);
});

function fetchRows({ limit=10, offset=0, orderBy=id}) {


ES6 console.log(limit, offset, orderBy);
});
ECMAScript 6: let + const

Remember var hoisting?

JavaScript uses block syntax, but does not use block scope

<script>
var x = 1;
function f() {
if (true) {
var x = 2;
}
return x;
}
f()
</script>
ECMAScript 6: let + const

Variable declarations are hoisted to the beginning of the


function body

<script>
var x;
<script> var f;
var x = 1; x = 1;
function f() { f = function() {
if (true) { var x;
var x = 2; if (true) {
} x = 2;
return x; }
} return x;
f() // 2 }
</script> f() // 2
</script>
ECMAScript 6: let + const

Let-declarations are truly block-scoped

let is the new var

ES5 ES6
<script> <script>
var x = 1; let x = 1;
function f() { function f() {
if (true) { if (true) {
var x = 2; let x = 2;
} }
return x; return x;
} }
f() // 2 f() // 1
</script> </script>
ECMAScript 6: let + const

Let-declarations are truly block-scoped

let is the new var

ES5 ES6
<script> <script>
var x = 1; let x = 1;
function f() { function f() {
if (true) { if (true) {
var x = 2; let x = 2;
} }
return x; return x;
} }
f() // 2 f() // 1
</script> </script>
ECMAScript 6: let + const

Const-declarations are single-assignment

Static restrictions prevent use before assignment

More like Java final than C++ const: the value referred to by a
const variable may still change

function f() {
const x = g(x); // static error
const y = { message: hello };
y = { message: world }; // static error
y.message = world; // ok
}
ECMAScript 6: tail calls

Calls in tail-position guaranteed not to consume stack space

Makes recursive algorithms practical for large inputs

function count(list, acc = 0) {


if (!list) {
return acc;
}
return count(list.next, acc + 1);
}

ES5 ES6
count(makeList(1000000)); count(makeList(1000000));
// Error: StackOverflow // 1000000
ECMAScript 6: improving modularity

Classes (with single-inheritance)

Enhanced object literals

Modules
ECMAScript 6: classes

All code inside a class is implicitly opted into strict mode!

function Point(x, y) { class Point {


this.x = x; constructor(x, y) {
this.y = y; this.x = x;
} this.y = y;
}
Point.prototype = {
toString: function() { toString() {
return "[Point...]"; return "[Point...]";
} }
} }

var p = new Point(1,2); var p = new Point(1,2);


p.x; p.x;
p.toString(); p.toString();
ECMAScript 6: classes

All code inside a class is implicitly opted into strict mode!

function Point(x, y) { class Point {


this.x = x; constructor(x, y) {
this.y = y; this.x = x;
} this.y = y;
}
Point.prototype = {
toString: function() { toString() {
return "[Point...]"; return "[Point...]";
} }
} }

var p = new Point(1,2); var p = new Point(1,2);


p.x; p.x;
p.toString(); p.toString();
ECMAScript 6: classes

Single-inheritance, super-calls, static members

class Point3D extends Point {


constructor(x, y, z) {
super(x,y);
this.z = z;
}

static getOrigin() {
return new Point3D(0,0,0);
}
}
ECMAScript 6: enhanced object literals

New syntax within object literals in-line with new class syntax

var parent = {}; var parent = {};


var foo = 0; var foo = 0;
var key = hello; var key = hello;
var obj = { var obj = {
foo: foo, __proto__: parent,
toString: function() { foo,
return foo; toString() {
} return foo;
}; },
obj.__proto__ = parent; [key]: 42
obj[key] = 42; };
ECMAScript 6: enhanced object literals

New syntax within object literals in-line with new class syntax

var parent = {}; var parent = {};


var foo = 0; var foo = 0;
var key = hello; var key = hello;
var obj = { var obj = {
foo: foo, __proto__: parent,
toString: function() { foo,
return foo; toString() {
} return foo;
}; },
obj.__proto__ = parent; [key]: 42
obj[key] = 42; };
ECMAScript 6: modules

All code inside a module is implicitly opted into strict mode!

<script>
<script type=module
var x = 0; // global
name=myLib>
var myLib = {
var x = 0; // local!
inc: function() {
export function inc() {
return ++x;
return ++x;
}
}
};
</script>
</script>

<script type=module>
<script>
import { inc } from myLib;
var res = myLib.inc();
var res = inc();
</script>
</script>
ECMAScript 6: modules

All code inside a module is implicitly opted into strict mode!

<script>
<script type=module
var x = 0; // global
name=myLib>
var myLib = {
var x = 0; // local!
inc: function() {
export function inc() {
return ++x;
return ++x;
}
}
};
</script>
</script>

<script type=module>
<script>
import { inc } from myLib;
var res = myLib.inc();
var res = inc();
</script>
</script>
ECMAScript 6: modules

There is much more to be said about modules

Module loader API

Dynamic (async) module loading

Compilation hooks (e.g. transform cs to js at load-time)

Load code in isolated environments with their own global


object

Inspiration from popular JS module systems like commonjs,


requireJS
ECMAScript 6: improving control flow

Iterators

Generators

Promises

async/await [tentative ES7 sneak peek]


ECMAScript 6 Iterators
function fibonacci() {
var pre = 0, cur = 1;
return {
next: function() {
var temp = pre;
pre = cur;
cur = cur + temp;
return { done: false, value: cur }
}
}
}
ES5 ES6
var iter = fibonacci();
var nxt = iter.next(); for (var n of fibonacci) {
while (!nxt.done) { if (n > 100)
var n = nxt.value; break;
if (n > 100) print(n);
break; }
print(n);
nxt = iter.next();
}
// generates 1, 1, 2, 3, 5, 8, 13, 21,
ECMAScript 6 Iterators
function fibonacci() {
var pre = 0, cur = 1;
return {
next: function() {
var temp = pre;
pre = cur;
cur = cur + temp;
return { done: false, value: cur }
}
}
}
ES5 ES6
var iter = fibonacci();
var nxt = iter.next(); for (var n of fibonacci) {
while (!nxt.done) { if (n > 100)
var n = nxt.value; break;
if (n > 100) print(n);
break; }
print(n);
nxt = iter.next();
}
// generates 1, 1, 2, 3, 5, 8, 13, 21,
ECMAScript 6 Generators

A generator function implicitly creates and returns an iterator

ES5 ES6
function fibonacci() { function* fibonacci() {
var pre = 0, cur = 1; var pre = 0, cur = 1;
return { for (;;) {
next: function() { var tmp = pre;
var tmp = pre; pre = cur;
pre = cur; cur = cur + tmp;
cur = cur + tmp; yield cur;
return { done: false, value: cur } }
} }
}
}
ECMAScript 6 Generators

A generator function implicitly creates and returns an iterator

ES5 ES6
function fibonacci() { function* fibonacci() {
var pre = 0, cur = 1; var pre = 0, cur = 1;
return { for (;;) {
next: function() { var tmp = pre;
var tmp = pre; pre = cur;
pre = cur; cur = cur + tmp;
cur = cur + tmp; yield cur;
return { done: false, value: cur } }
} }
}
}
ECMAScript 6 Promises

A promise is a placeholder for a value that may only be available in


the future
readFile(hello.txt, function (err, content) {
if (err) {
// handle error
ES5 } else {
// use content
}
})

var pContent = readFile(hello.txt);


pContent.then(function (content) {
// use content
ES6 }, function (err) {
// handle error
});
ECMAScript 6 Promises

A promise is a placeholder for a value that may only be available in


the future
readFile(hello.txt, function (err, content) {
if (err) {
// handle error
ES5 } else {
// use content
}
})

var pContent = readFile(hello.txt);


var p2 = pContent.then(function (content) {
// use content
ES6 }, function (err) {
// handle error
});
ECMAScript 6 Promises

Promises can be chained to avoid callback hell

// step2(value, callback) -> void // promisedStep2(value) -> promise

step1(function (value1) { Q.fcall(promisedStep1)


step2(value1, function(value2) { .then(promisedStep2)
step3(value2, function(value3) { .then(promisedStep3)
step4(value3, function(value4) { .then(promisedStep4)
// do something with value4 .then(function (value4) {
}); // do something with value4
}); })
}); .catch(function (error) {
}); // handle any error here
})
.done();

Example adapted from https://github.com/kriskowal/q


ECMAScript 6 Promises

Promises already exist as a library in ES5

Personal favorite: Q (cf. https://github.com/kriskowal/q )

npm install q

Then why standardize?

Wide disagreement on a single Promise API. ES6 settled on an


API called Promises/A+. See promisesaplus.com

Standard API allows platform APIs to use Promises as well

W3Cs latest DOM APIs already use promises


ECMAScript 7: async/await

async/await is a C# 5.0 feature that enables asynchronous


programming using direct style control flow (i.e. no callbacks)

ES6 ES7
// promisedStep2(value) -> promise // step2(value) -> promise

Q.fcall(promisedStep1) (async function() {


.then(promisedStep2) try {
.then(promisedStep3) var value1 = await step1();
.then(promisedStep4) var value2 = await step2(value1);
.then(function (value4) { var value3 = await step3(value2);
// do something with value4 var value4 = await step4(value3);
}) // do something with value4
.catch(function (error) { } catch (error) {
// handle any error here // handle any error here
}) }
.done(); }())
async/await in ECMAScript 6

Generators can be used as async functions, with some tinkering

E.g. using Q in node.js (>= 0.11.x with --harmony flag)

ES7 ES6
(async function() { Q.async(function*() {
try { try {
var value1 = await step1(); var value1 = yield step1();
var value2 = await step2(value1); var value2 = yield step2(value1);
var value3 = await step3(value2); var value3 = yield step3(value2);
var value4 = await step4(value3); var value4 = yield step4(value3);
// do something with value4 // do something with value4
} catch (error) { } catch (error) {
// handle any error here // handle any error here
} }
}()) })()
async/await in ECMAScript 6

Generators can be used as async functions, with some tinkering

E.g. using Q in node.js (>= 0.11.x with --harmony flag)

ES7 ES6
(async function() { Q.async(function*() {
try { try {
var value1 = await step1(); var value1 = yield step1();
var value2 = await step2(value1); var value2 = yield step2(value1);
var value3 = await step3(value2); var value3 = yield step3(value2);
var value4 = await step4(value3); var value4 = yield step4(value3);
// do something with value4 // do something with value4
} catch (error) { } catch (error) {
// handle any error here // handle any error here
} }
}()) })()
ECMAScript 6 template strings

String interpolation (e.g. for templating) is very common in JS

Vulnerable to injection attacks

function createDiv(input) {
return "<div>"+input+"</div>";
};

createDiv("</div><script>");
// "<div></div><script></div>"
ECMAScript 6 template strings

Template strings combine convenient syntax for interpolation


with a way of automatically building the string

function createDiv(input) {
return html`<div>${input}</div>`;
};

createDiv("</div><script>");
// "<div>&lt;/div&gt;&lt;script&gt;</div>"
ECMAScript 6 template strings

User-extensible: just sugar for a call to a template function

Expectation that browser will provide html, css template functions

function createDiv(input) {
return html(["<div>","</div>"], input);
};

createDiv("</div><script>");
// "<div>&lt;/div&gt;&lt;script&gt;</div>"
ECMAScript 6 template strings

The template tag is optional. If omitted, just builds a string.

let str = `1 plus 2 is ${1 + 2}`;

And yes, template strings can span multiple lines, so we finally


have multi-line strings:

function createPoem() {
return `hello
world`;
};
ECMAScript 6 template strings: closing note

Template strings are not to be confused with template languages


such as handlebars, mustache, etc.

Often used to generate strings

Contain instructions such as loops, conditionals, etc.


ECMAScript 6: improving collections

Up to ES5: arrays and objects. Objects (ab?)used as maps of


String to Any

ES6 brings Map, Set, WeakMap, WeakSet

let m = new Map();


m.set(a, 42);
m.get(a) === 42;

Also support Objects as keys (not just Strings)

Weak* variants automatically remove entry when key becomes


garbage. Ideal for building caches.
ECMAScript 6: improving reflection

Proxies

Dynamic proxy objects: objects whose behavior can be


controlled in JavaScript itself

Useful to create generic (i.e. type-independent) object


wrappers
ECMAScript 6 proxies
var proxy = new Proxy(target, handler);

handler.get(target, foo) handler

handler.set(target, foo, 42)

reflection
application

proxy.foo
proxy target
proxy.foo = 42
Part III
Using ECMAScript 6 today, and what lies beyond
ECMAScript 6: timeline

Current ES6 draft is feature-complete. Available online:


http://people.mozilla.org/~jorendor/es6-draft.html

Spec needs to be ratified by ECMA, targeting June 2015

However: browsers will not support ES6 overnight

Parts of ES6 already supported on some browsers today*

Use compilers in the meantime to bridge the ES5-ES6 gap

* see Juriy Zaytsevs (a.k.a. kangax) excellent compatibility tables


http://kangax.github.io/es5-compat-table/es6/ for current status
ECMAScript 6 support (april 2015)
ECMAScript 5 support (april 2015)
ECMAScript 6 compilers

Compile ECMAScript 6 to ECMAScript 5

Google Traceur: mature and quite feature-


complete. Aims to be fully spec-compliant.

Babel: focus on producing readable (as-if hand-


written) ES5 code. Supports JSX.

Microsoft TypeScript: technically not ES6 but


roughly a superset of ES6. Bonus: type inference
and optional static typing.
Going forward

ECMAScript 6 ocially called ECMAScript 2015

Goal is to have yearly spec releases from now on

Hence, not sure there will ever be an ECMAScript 7 as such


ES7 Proposals on the table

Again, too many to list in detail. See https://github.com/tc39/ecma262


Wrap-up
Take-home messages

ECMAScript 5 strict mode: a saner basis for the future evolution of


JavaScript

Opt-in subset that removes some of JavaScripts warts. Use it!


Take-home messages

ECMAScript 6 is a major upgrade to the language

Expect browsers to implement the upgrade gradually and piecemeal

Use ES6 to ES5 compilers to bridge the gap

You can use ES6 today!


Where to go from here?

Warmly recommended: Doug Crockford on JavaScript


http://goo.gl/FGxmM (YouTube playlist)
Where to go from here?

Dave Herman
Mozilla representative on TC39
Additional references

ECMAScript 5 and strict mode: Changes to JavaScript Part 1:


EcmaScript 5 (Mark S. Miller, Waldemar Horwat, Mike Samuel), Google
Tech Talk (May 2009)

ECMAScript latest developments: http://wiki.ecmascript.org and the


es-discuss@mozilla.org mailing list.

ECMAScript 6: Axel Rauschmayers blog: http://www.2ality.com

Using ES6 today: R. Mark Volkmann: Using ES6 Today!


http://sett.ociweb.com/sett/settApr2014.html
Thanks for listening!

The road to ES6, and beyond

A tale about JavaScripts past, present and future


Tom Van Cutsem
jsconf.be 2015

@tvcutsem

You might also like