This document provides an overview of several new features introduced in ECMAScript 6 (ES6), including:
1. Arrow functions which provide a shorter syntax for writing function expressions and retain the lexical this value.
2. Block scoping with let which allows block-level scoping of variables replacing the need for IIFEs in ES5. const is also introduced for single-assignment constants.
3. String templates which make it easier to construct strings and allow interpolation of variables and expressions.
3. A Brief History of Time...
A Brief History of Time...
Official name of the language is ECMAScript
ECMA is the Standardizations Body
TC39 is the committee working on the
standards.
in 2015, ECMA decided to do yearly standards,
hence the renaming.
4. ES6 Browser Support
ES6 Browser Support
Current browser support for ES6 is great on the desktop -
not so much elsewhere
http://kangax.github.io/compat-table/es6/
Current development uses ES6/next features
through the use of transpilers like Babel
5. Arrow Functions
Arrow Functions
Arrows are a function shorthand using the => syntax. They are
syntactically similar to the related feature in C#, Java 8 and
CoffeeScript. They support both expression and statement
bodies. Unlike functions, arrows share the same lexical this as
their surrounding code.
6. Arrow Functions
var list = [1,2,3,4,5];
list.map(function(n) {
return n * 2;
}, this);
list.map(function(n) {
return n * 2;
}.bind(this));
In ES5, retaining the context of this in function expressions
was typically done via Function#bind(); or through passing an
execution context those few standard functions that allowed
one.
var list = [1,2,3,4,5];
list.map(n => n * 2);
ES5
ES5 ES6
ES6
9. Block Scoping
var a = 5;
var b = 10;
if (a === 5) {
// IIFE !!!
(function () {
var a = 4;
b = 1;
console.log(a); // 4
console.log(b); // 1
})();
}
console.log(a); // 5
console.log(b); // 1
ES5 required IIFEs in order to create pseudo-block scoping.
ES6 gives us let, which is scoped to the enclosing block.
var a = 5;
var b = 10;
if (a === 5) {
let a = 4; // scope inside if-block
var b = 1; // scope inside function
console.log(a); // 4
console.log(b); // 1
}
console.log(a); // 5
console.log(b); // 1
ES5
ES5 ES6
ES6
10. Block Scoping
// define as a non-writable `constant`
// and give it a value
Object.defineProperties(window, {
pi: {
value: 3.14159265359,
enumerable: true,
writable: false
}
});
// var pi = 7;
// Attempt to overwrite the constant
pi = 15;
console.log('Slice of pi: ' + pi);
// 3.14159265359
const pi = 3.14159265359;
// Attempt to overwrite the constant
pi = 15;
// TypeError: Assignment to constant
console.log('Slice of pi: ' + pi);
// 3.14159265359
// Never executes...
ES5
ES5 ES6
ES6
11. String Templates
String Templates
Template strings provide syntactic sugar for constructing
strings. This is similar to string interpolation features in
Perl, Python and more. Optionally, a tag can be added to
allow the string construction to be customized, avoiding
injection attacks or constructing higher level data
structures from string contents.
12. String Templates
var name = 'Dan';
var dan = {
projects: ['redux','react-dnd']
};
// concatenation
console.log(name + ' Abramov');
//=> Dan Abramov
// joining
console.log(
['Known for ', dan.projects[0]].join('')
);
//=> Known for redux
ES5 had nothing similar. You would just concatenate strings
with expressions. ES6 allows interpolation of variables,
expressions and functions inside template strings.
ES5
ES5
13. String Templates
const name = 'Dan';
const n = 10;
const dan = {
projects: ['redux','react-dnd']
};
const fn = () => 'reducers';
// variables
console.log(`${name} Abramov`);
// objects
console.log(`Known for ${dan.projects[0]}`);
// expression interpolation
console.log(`${n} + 2 = ${n + 2}`);
// functions
console.log(`I love ${fn()}`);
ES6
ES6
14. String Templates
// Multiline strings
// 1. escaping - white space retained
// 2. concatenation
console.log(
'This string spans n
multiple lines. It's crazy!n' +
'It's a bit harder to read'
);
//=> This string spans
//=> multiple lines. It's crazy!
//=> It's a bit harder to read
ES5
ES5
// Multiline strings
// - white space retained
console.log(
`This string spans
multiple lines. It's crazy!`
);
//=> This string spans
//=> multiple lines. It's crazy!
ES6
ES6
15. Object Properties
Object Properties
Object Initializer Shorthand
Object Method Assignment
Computed Properties
Object literals are extended to support setting the
prototype at construction, shorthand for foo: foo
assignments, defining methods and making super calls.
Together, these also bring object literals and class
declarations closer together, and let object-based design
benefit from some of the same conveniences.
16. Object Properties
function getPoint() {
var x = 1;
var y = 10;
return { x: x, y: y };
}
getPoint();
//=> { x: 1, y: 10 }
With property shorthand notation, if the property name and
value variable are the same, no need to repeat yourself.
function getPoint() {
var x = 1;
var y = 10;
return { x, y };
}
getPoint()
//=> { x: 1, y: 10 }
ES5
ES5 ES6
ES6
17. Object Properties
var object = {
value: 42,
toString: function toString() {
return this.value;
}
};
object.toString() === 42;
// -> true
With object method assignment shorthand you can shorten
method declarations on objects/classes as well.
var object = {
value: 42,
toString() {
return this.value;
}
};
console.log(object.toString() === 42);
// -> true
ES5
ES5 ES6
ES6
18. Object Properties
var prefix = 'foo';
var obj = {};
obj[prefix + 'bar'] = 'hello';
obj[prefix + 'baz'] = 'world';
console.log(obj['foobar']);
// -> hello
console.log(obj['foobaz']);
// -> world
With ES6 we now have the ability to use computed property
names as well. You can evaluate any expression within [ ].
var foo = 'foo';
var fn = () => 'foo';
var obj = {
[foo + 'bar']: 'hello',
[fn() + 'baz']: 'world'
};
console.log(obj['foobar']);
// -> hello
console.log(obj['foobaz']);
// -> world
ES5
ES5 ES6
ES6
19. Destructuring Assignments
Destructuring Assignments
Destructuring allows binding using pattern matching,
with support for matching arrays and objects.
Destructuring is fail-soft, similar to standard object
lookup foo["bar"], producing undefined values when not
found.
20. Destructuring
var foo = { bar: 'Kyle', baz: 'Simpson' };
var bar = foo[bar];
var baz = foo[baz];
// -> bar: 'Kyle', baz 'Simpson'
var list = [1,2,3];
var one = list[0];
var two = list[1];
var three = list[2];
// -> one: 1, two: 2, three: 3
Binds the values from one Array or Object to another.
const foo = { bar: 'Kyle', baz: 'Simpson' };
const {bar, baz} = foo;
// -> bar: 'Kyle', baz 'Simpson'
const list = [1,2,3];
const [one, two, three] = list;
// -> one: 1, two: 2, three: 3
ES5
ES5
ES6
ES6
21. Destructuring
You can also map destructured objects to aliases as well.
const foo = { bar: 'Kyle', baz: 'Simpson' };
const { bar: a, baz: b } = foo;
// -> bar: 'Kyle', baz 'Simpson'
ES6
ES6
22. Destructuring
Or even pull out deeply nested properties
const person = {
name: 'Steve',
things: { one: 1, two: 2 },
years: [1975, 1995, 2015]
};
const { name, things: { one }} = person;
// -> name: Steve
// -> one: 1
// But, if it's not there
const stuff = { one: 1, two: 2 };
const { three } = stuff;
// -> three: undefined
ES6
ES6
23. Destructuring
Plus, it makes it easier to do things like swapping variables
without using an auxiliary. Or pulling out properties
dynamically using computed property names.
let a = 10, b = 20;
[a, b] = [b, a];
// -> a = 20, b = 10
const key = 'doge';
const { [key]: foo } = { doge: 'such bar!' };
// -> foo = such bar!
// Assign defaults (in case of undefined)
const wow = { such: 'awesome' };
const { much='missing' } = wow;
// -> much = missing
// Skip over elements in arrays
let [,,c,d] = [1,2,3,4,5];
// -> c = 3
// -> d = 4
ES6
ES6
24. Function Arguments
Function Arguments
Default Arguments
Spread
Rest
Callee-evaluated default parameter values. Turn
an array into consecutive arguments in a function
call. Bind trailing parameters to an array. Rest
replaces the need for arguments and addresses
common cases more directly.
25. Default Argument Values
function iam(name) {
(name === undefined) && (name="Batman");
console.log("I am " + name + '!');
}
iam();
// -> I am Batman!
Similar to the default assignments used in destructuring,
functions allow you assign default values as well. If the
parameter passed is undefined, it gets the default.
function iam(name="batman") {
console.log(`I am ${name}!`);
}
iam();
// -> I am Batman!
ES5
ES5
ES6
ES6
26. Defaults & Destructuring
You can even use destructuring and defaults on function
arguments
function random ({ min=1, max=300 }) {
return Math.floor(Math.random() * (max - min)) + min;
}
random({});
// -> 174
random({max: 24});
// -> 18
// Or, make the whole argument optional
function random ({ min=1, max=300 }={}) {
return Math.floor(Math.random() * (max - min)) + min;
}
random();
// -> 133
ES6
ES6
27. The spread operator pulls individual items out of a collection
(Array or Object).
function reducer(state={}, action) {
switch(action.type) {
case 'SET_AGE': return {
...state,
age: action.age
};
default:
return state;
}
}
const state = { name: 'Dave', age: 40 };
const action = {
type: 'SET_AGE',
age: 41
};
reducer(state, action);
// -> { name: 'Dave', age: 41 }
ES6
ES6
... spread operator
28. var nums = [4,1,9,5];
Math.max.apply(null, nums);
// -> 9
let a = [1,2,3];
let b = [4,5,6];
// join
var c = a.concat(b);
// -> c = [1,2,3,4,5,6]
// copy
var d = [].slice.call(c, 0);
// -> d = [1,2,3,4,5,6]
// splice
var e = [0,7,8];
var f = e.slice(0,1)
.concat(c, e.slice(1), [9,10]);
// -> f = [0,1,2,3,4,5,6,7,8,9,10]
Works with Arrays as well (non-mutating).
let nums = [4,1,9,5];
Math.max(...nums);
// -> 9
let a = [1,2,3];
let b = [4,5,6];
// join
let c = [...a, ...b];
// -> c = [1,2,3,4,5,6]
// copy
let d = [...c];
// -> d = [1,2,3,4,5,6]
// splice
let e = [0, ...d, 7, 8, ...[9,10]];
// -> e = [0,1,2,3,4,5,6,7,8,9,10]
ES5
ES5 ES6
ES6
... spread operator
29. function join(sep /*, ...args*/) {
var args = [].slice.call(arguments, 1);
return args.join(sep);
}
join(', ', 'john', 'bobby', 'ted')
// -> 'john, bobby, ted'
The rest operator (or, gather) allows us to pull values into a
collection Array or Object.
const join = (sep, ...args) => args.join(sep);
join(':', "one", "two", "three");
// -> one:two:three
ES5
ES5
ES6
ES6
... rest operator
30. You can even use it with destructuring to gather values.
var list = [1,2,3,4,5];
var [head, ...tail] = list;
// -> head = 1
// -> tail = [2,3,4,5]
var list = [1,2,3,4,5];
var [head, ...tail] = list;
console.log(head, tail);
var passed = {
className: 'panel',
style: { color: '#369'},
title: 'Panel',
active: true
};
var { className, style, ...props } = passed;
// -> className = 'panel'
// -> styles = { color: '#369' }
// -> props = { title: 'Panel', active: true }
ES6
ES6
... rest operator
31. Iterators & Arrays
Iterators & Arrays
Iterators allow us to traverse a collection. Generalize for..in
to custom iterator-based iteration with for..of. Array#from
allows us to convert array-like collections into real arrays.
32. Iterators & Arrays
var a = [1,2,3];
a.forEach(function (element) {
console.log(element);
});
// -> 1 2 3
// Using a for loop
var a = [1,2,3];
for (var i = 0; i < a.length; ++i) {
console.log(a[i]);
}
// -> 1 2 3
// Uses an iterator behind the scenes
for (let element of [1, 2, 3]) {
console.log(element);
}
// => 1 2 3
ES5
ES5
ES6
ES6
33. Iterators
function iteratorFor(list) {
var i = 0;
return {
next: function() {
return {
value: list[i++],
done: i > list.length
};
}
}
}
var iter = iteratorFor([1,2,3]);
var res = iter.next();
while (!res.done) {
console.log(res);
res = iter.next();
}
// -> Same output as right-side
What is an iterator? ES6 let's us access them via predefined
Symbol properties.
let iter = [1, 2, 3][Symbol.iterator]();
console.log(iter.next());
// -> {value: 1, done: false}
console.log(iter.next());
// -> {value: 2, done: false}
console.log(iter.next());
// -> {value: 3, done: false}
console.log(iter.next());
// -> {value: undefined, done: true}
ES5
ES5 ES6
ES6
34. Iterators with Generators
You can write your own iterators using ES6 generator
functions and yield.
function* iteratorFor(list) {
for (let item of list) {
yield item;
}
}
const iter = iteratorFor([1,2,3]);
for (let value of iter) {
console.log(value);
}
// -> 1 2 3
// can't use iter again
let iter2 = iteratorFor([1,2,3]);
console.log([...iter2]);
// -> [1,2,3]
ES6
ES6
35. Classes
Classes
ES2015 classes are a simple sugar over the
prototype-based OO pattern. Having a single,
convenient, declarative form makes class patterns
easier to use, and encourages interoperability.
Classes support prototype-based inheritance, super
calls, instance and static methods and constructors.
36. // Person "Class"
function Person(name) {
this.name = name;
}
Person.type = 'person';
Person.prototype.greet = function() {
return 'Hello, my name is ' + this.name + '.';
}
Person.prototype.typeOf = function() {
return this.constructor.type;
}
// Employee "Class"
function Employee(company, name) {
Person.call(this, name);
this.company = company;
}
Employee.type = 'employee';
// setup inheritance via prototype chain
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
// Override greet method
Employee.prototype.greet = function() {
return Person.prototype.greet.call(this) +
' I work at ' + this.company
}
ES5
ES5
37. ES5 "Classes"
// create an instance
var Dave = new Employee('OCI', 'David');
// call a method
Dave.greet();
// -> Hello, my name is David. I work at OCI
// access "static" property via method
console.log('Dave is an ' + Dave.typeOf());
// -> Dave is an employee
ES5
ES5
38. ES6 Classes
class Person {
static type = 'person';
constructor(name) {
this.name = name;
}
typeOf() { return this.constructor.type; }
greet() { return `Hello, my name is ${this.name}`; }
}
class Employee extends Person {
static type = 'employee';
constructor(company, name) {
super(name);
this.company = company;
}
greet() {
return `${super.greet()}. I work at ${this.company}`;
}
}
ES6
ES6
39. ES6 Classes
// create an instance
const Dave = new Employee('OCI', 'David');
// invoke methods
console.log(Dave.greet());
// -> Hello, my name is David. I work at OCI
// access static props via method
console.log(`Dave is an ${Dave.typeOf()}`);
// -> employee
ES6
ES6
40. Modules
Modules
import & export
named exports
default exports
importing defaults & named exports
Language-level support for modules for component
definition. Codifies patterns from popular JavaScript
module loaders (AMD, CommonJS). Runtime behaviour
defined by a host-defined default loader. Implicitly async
model – no code executes until requested modules are
available and processed.
41. Module Styles
// app.js
var math = require('lib/math');
math.sum(math.pi, math.pi);
Currently, the module loading spec is not defined completely and not
implemented in any engine. Node supports CommonJS; but other
async loading module formats exist like AMD and UMD.
// app.js
import math from 'lib/math';
math.sum(math.pi, math.pi)
ES5
ES5 ES6
ES6
// lib/math.js
exports.sum = sum;
function sum(x, y) {
return x + y;
}
var pi = exports.pi = 3.141593;
ES5
ES5
// lib/math.js
export function sum(x, y) {
return x + y;
}
export var pi = 3.141593;
ES6
ES6
42. Named & Default Exports
// Named exports
function sum(a,b) {
return a + b;
}
exports.sum = sum;
function div(a,b) {
return a / b;
}
exports.div = div;
// Module 'default' export
exports['default'] = function(n) {
return n * n;
}
module.exports = Object.assign(
exports['default'],
exports
);
Both CommonJS and ES6 allow for named exports and a
"default" export.
// Named exports
export sum = (a,b) => a + b;
export div = (a,b) => a / b;
// default export
export default (n) => n * n;
ES5
ES5 ES6
ES6
43. ES6 Modules
You can only have 1 default export per module. But you can
import the default or named exports in a number of ways.
// lib/math.js
// named exports
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
// default export
export default function(...nums) {
return Math.max(...nums);
}
ES6
ES6
import max from 'lib/math';
max(1,2,3); // -> 3
import { square, diag } from 'lib/math';
square(2) // -> 4
diag(2,4) // -> 4.47213595499958
import max, { square, sqrt } from 'lib/math';
max(3,1,5); // -> 5
square(4); // -> 16
sqrt(9); // -> 3
ES6
ES6