Intro to ES6
Mike North, Principal Engineer, Yahoo Inc.
What is ECMAScript?
The JavaScript standard (ECMA-262)
Common Implementations
JavaScript JScript ActionScript
TC39 - Task group
How did we get to ES6?
1997 ES1
1998 ES2 - Alignment with other standards
1999 ES3 - Regex, String utils, try/catch
ES4 - ABANDONED
2009 ES5 - Strict mode, Object , JSON , and Array utils
2011 ES5.1 - Alignment with new standards
2015 ES6
ES6
ES6
Scoping
-
Block scoping
-
Destructuring
-
Default param values
-
Rest parameters
-
Spread
Modularity
-
Modules
-
Standard Modules
-
Multiple Globals
-
Object Literals
-
Classes
-
Symbols
Control
-
Tail calls
-
Iterators
-
For-of loops
-
Generators
-
Array comprehensions
-
Arrow functions
Collections
-
Sets
-
Maps
-
Weak maps
Virtualization
-
Proxies
-
Loaders
Data
-
Binary data
-
Template strings
-
Octal/Binary literals
-
Unicode syntax
Also... Array, Object, Number, Regex, String, Math, Function improvements
Native Support
Polyfills
- 6to5 (merged with esnext)
- Traceur
- es6-transpiler
- es6now
- jstransform
Scoping
- Block scoping
- Destructuring
- Default parameter values
- Rest parameters
- Spread
Block Scoping: Let
let
A new keyword:
Conceptually similar to but defines a variable only within the current
var
Works in YAM+
Block Scoping: Let
function log(msg) { console.log("LOG MESSAGE: " + msg); }
function f(x) {
if (x > 0) {
let { log, sin, cos } = Math;
// log is now Math.log
console.log('log(' + x + ')= ' + log(5));
}
// log is now back to our logging function
log("done computing f()");
}
f(3);
log('hello world!');
log(3)= 1.6094379124341003 done computing f() hello world!
ES6
Block Scoping: Let
function log(msg) {
console.log("LOG MESSAGE: " + msg);
}
function f(x) {
if (x > 0) {
let { log, sin, cos } = Math;
// log is now Math.log
console.log('log(' + x + ')= '
+ log(5));
}
// log is now back to our logging function
log("done computing f()");
}
f(3);
log('hello world!');
"use strict";
function log(msg) {
console.log("LOG MESSAGE: " + msg);
}
function f(x) {
if (x > 0) {
var _log = Math.log;
var sin = Math.sin;
var cos = Math.cos;
// log is now Math.log
console.log("log(" + x + ")= "
+ _log(5));
}
// log is now back to
// our logging function
log("done computing f()");
}
f(3);
log("hello world!");
ES6 -> ES5
ES6
ES5
Block Scoping: Const
const
A new keyword:
Conceptually similar to but defines a read-only variable. Writing to this variable throws a transpile error
let
Works in YAM+
Block Scoping: Const
const y = {};
y['a'] = 5;
console.log(y)
y = {}; //transpile error
const f = function () {console.log('hi');}
f(); //"hi"
f = function () {console.log('abc');} //transpile error
ES6
Block Scoping: Const
ES6 -> ES5
const y = {};
y['a'] = 5;
// transpile error
// y = {};
const f = function () {console.log('hi');}
f(); // "hi"
// transpile error
// f = function () {console.log('abc')l}
ES6
"use strict";
var y = {};
y.a = 5;
// transpile error
// y = {};
var f = function () {
console.log("hi");
};
f(); // "hi"
// transpile error
// f = function () {console.log('abc')l}
ES5
Block Scoping: Const
- A pure transpile-time modification
- May be expensive as the codebase becomes large
Destructuring
Pattern matching for objects and arrays, in assignment and function parameters
Works in YAM+
Destructuring: Assignment
// Example 1, returning an object
function stats(arr) {
var sum = arr.reduce(
function(c,x) {
return (c || 0) + x;
}
);
return {
sum: sum,
mean: arr.length === 0
? 0
: (sum / arr.length)
};
}
var {sum, mean} = stats([1, 2, 3]);
console.log('Sum=', sum,
' Mean=', mean);
ES6
"use strict";
// Example 1, returning an object
function stats(arr) {
var sum = arr.reduce(function (c, x) {
return (c || 0) + x;
});
return {
sum: sum,
mean: arr.length === 0
? 0
: sum / arr.length
};
}
var _stats = stats([1, 2, 3]);
var sum = _stats.sum;
var mean = _stats.mean;
console.log("Sum=", sum,
" Mean=", mean);
ES5
Destructuring: Assignment
var [b,c,a] = [1,,2];
console.log("a=", a); //2
console.log("c=", c); //undefined
ES6
"use strict";
var _ref = [1,, 2];
var b = _ref[0];
var c = _ref[1];
var a = _ref[2];
console.log("a=", a); //2
console.log("c=", c); //undefined
ES5
Destructuring: Arguments
function divide({
numerator: n,
denominator: d }) {
return n/d;
}
console.log('divide 6/4',
divide({numerator: 6, denominator: 4})
);
ES6
"use strict";
function divide(_ref) {
var n = _ref.numerator;
var d = _ref.denominator;
return n / d;
}
console.log("divide 6/4",
divide({ numerator: 6, denominator: 4})
);
ES5
Default Parameter Values
Allows specification of a default value for function parameters.
Works in YAM+
Default Parameter Values
// Simple values
function addThree(a, b=4) {
return a + b + 3;
}
addThree(4);
addThree(4,5);
// Works with arrays and objects too!
function normalizePayload(
payload={users: []}, type) {
console.log(payload);
};
ES6
"use strict";
// Simple values
function addThree(a) {
var b = arguments[1] === undefined
? 4
: arguments[1];
return a + b + 3;
}
addThree(4);
addThree(4, 5);
// Works with arrays and objects too!
function normalizePayload(_x, type) {
var payload = arguments[0] === undefined
? { users: [] }
: arguments[0];
console.log(payload);
};
ES5
Rest Parameters
- Kind of like the "arguments" object, except altering values has no weird effects
- It's a real array
Works in YAM+
Rest Parameters
var t = "Hello %s!"
function greet(template, ...args) {
return args.map(function(arg) {
return t.replace('%s', arg);
}).join(', ');
}
console.log(greet(t, 'Mike', 'Dave', 'Steve'));
// Hello Mike!, Hello Dave!, Hello Steve!
ES6
"use strict";
var t = "Hello %s!";
function greet(template) {
for (var _len = arguments.length,
args = Array(_len > 1
? _len - 1
: 0),
_key = 1;
_key < _len;
_key++) {
args[_key - 1] = arguments[_key];
}
return args.map(function (arg) {
return t.replace("%s", arg);
}).join(", ");
}
console.log(greet(t, "Mike", "Dave", "Steve"));
// Hello Mike!, Hello Dave!, Hello Steve!
ES5
Rest Parameters
var t = "Hello %s!"
function greet(template, ...args) {
return args.map(function(arg) {
return t.replace('%s', arg);
}).join(', ');
}
console.log(greet(t, 'Mike', 'Dave', 'Steve'));
// Hello Mike!, Hello Dave!, Hello Steve!
ES6
"use strict";
var t = "Hello %s!";
function greet(template) {
for (var _len = arguments.length,
args = Array(_len > 1
? _len - 1
: 0),
_key = 1;
_key < _len;
_key++) {
args[_key - 1] = arguments[_key];
}
return args.map(function (arg) {
return t.replace("%s", arg);
}).join(", ");
}
console.log(greet(t, "Mike", "Dave", "Steve"));
// Hello Mike!, Hello Dave!, Hello Steve!
ES5
Spread
- Expands arrays to act like multiple variables
- A better Function.prototype.apply
- Easy array concatenation
Works in YAM+
Spread
var b = [2, 3];
var a = [1, ...b, 5];
console.log(a); // [1, 2, 3, 5]
a.push(...b);
console.log(a); // [1, 2, 3, 5, 2, 3]
ES6
"use strict";
var _toArray = function (arr) {
return Array.isArray(arr)
? arr
: Array.from(arr);
};
var b = [2, 3];
var a = [1].concat(_toArray(b), [5]);
console.log(a); // [1, 2, 3, 5]
a.push.apply(a, _toArray(b));
console.log(a); // [1, 2, 3, 5, 2, 3]
ES5
Spread
var b = [2, 3];
var a = [1, ...b, 5];
console.log(a); // [1, 2, 3, 5]
a.push(...b);
console.log(a); // [1, 2, 3, 5, 2, 3]
ES6
"use strict";
var _toArray = function (arr) {
return Array.isArray(arr)
? arr
: Array.from(arr);
};
function f(a, b, c) {
console.log("a=", a, "b=", b, "c=", c);
}
function a() {
var args = [1, 2, 3];
f.apply(undefined, _toArray(args));
}
a(); // a= 1 b= 2 c= 3
ES5
Modularity
- Modules
- Object Literals
- Classes
- Symbols
Modules
- Allows for better encapsulation of code on a per-file bases
- Built on patterns from YUI, AMD, CommonJS, etc...
- No code executes until requested modules are available and processed (async friendly)
Works in YAM+
Modules: Exports
export function sum(x, y) {
return x + y;
}
export var pi = 3.141593;
ES6
"use strict";
// lib/math.js
exports.sum = sum;
function sum(x, y) {
return x + y;
}
var pi = exports.pi = 3.141593;
exports.__esModule = true;
ES5
Modules: Imports
// app.js
import * as math from "lib/math";
alert("2π = " + math.sum(math.pi, math.pi));
ES6
"use strict";
var _interopRequireWildcard =
function (obj) {
return obj && obj.__esModule
? obj
: { "default": obj };
};
// app.js
var math = _interopRequireWildcard(
require("lib/math")
);
alert("2π = " + math.sum(math.pi, math.pi));
ES5
Object Literals
- Prototype and methods can be set at part of construction
- Super calls!
- Dynamic property names
Works in YAM+
Object Literals
var firstName = 'Mike',
lastName = 'North';
var x = {
firstName,
lastName,
['age']: 31,
toString() {
return JSON.stringify(this);
}
}
console.log(x);
ES6
"use strict";
var firstName = "Mike",
lastName = "North";
var x = (function () {
var _x = {};
_x.firstName = firstName;
_x.lastName = lastName;
_x.age = 31;
_x.toString = function toString() {
return JSON.stringify(this);
};
return _x;
})();
console.log(x);
ES5
Classes
- Syntactic sugar over prototypical inheritance
- Presents some of the same advantages as classical inheritance, in declarative form
- super calls
- instance methods
- static methods
- constructors
Works in YAM+
Classes
class Animal extends Object {
constructor (name='Animal') {
this.name = name
}
eat() {
console.log(this.name + " is eating");
}
}
class Canine extends Animal {
static numLegs() {return 4;}
constructor (name='Canine') {
super(name);
}
eat() {
super();
console.log('...and then chasing his tail');
}
}
class Dog extends Canine {
constructor (name='Dog') {
super(name);
}
}
var d = new Dog();
d.eat(); // Dog is eating ...and then chasing his tail
var dd = new Dog('Charlie');
dd.eat(); // Charlie is eating ...and then chasing his tail
console.log(Dog.numLegs()); // 4
ES6
class Dog extends Canine {
constructor (name='Dog') {
super(name);
}
}
var d = new Dog();
d.eat();
// Dog is eating ...and then chasing his tail
var dd = new Dog('Charlie');
dd.eat();
// Charlie is eating ...and then chasing his tail
console.log(Dog.numLegs());
// 4
ES6
Classes
- Remember, this is still prototypical inheritance
- All member data is set up in constructor
Symbols
- A new type of object
- Immutable
- Unique within a module
- Allows better hiding of private data
Works in YAM+
Needs polyfill
Symbols
// Create an object
var o = {};
// Create a symbol, with an optional name
var key = Symbol('a');
// Set a property of "o" using key
o[key] = 'testing';
// Create another symbol with an optional name
var other_key = Symbol('a');
console.log(other_key.toString()) // Symbol(testing)
// Retrieving the value we set above for key can't be accessed
console.log(o[other_key]); // undefined
// Properties under keys are by default not enumerable
console.log(o); // {}
ES6
Control
- Arrow Functions
- Array comprehensions
- Iterators
- For-of Loop
- Generators
- Generator Comprehensions
Arrow Functions
- Similar to C#, Java 8 concepts
- Behaves like a function, except "this" is always same as parent closure
Works in YAM+
Arrow Functions
var obj = {
items: ['apple', 'pear'],
formatItem: function(item) {
return item.toUpperCase();
},
print: function () {
console.log(
this.items.map(
x => this.formatItem(x)
)
);
}
};
obj.print();
ES6
"use strict";
var obj = {
items: ["apple", "pear"],
formatItem: function (item) {
return item.toUpperCase();
},
print: function () {
var _this = this;
console.log(this.items.map(
function (x) {
return _this.formatItem(x);
}
));
}
};
obj.print();
ES5
Comprehensions
- New ways of defining arrays using expressions instead of literal assignment
Works in YAM+
Needs polyfill
Comprehensions
var customers = [
{city: 'New York', name: 'Kay', age: 31},
{city: 'Seattle', name: 'Jo', age: 36}
];
var results = [
for(c of customers)
if (c.city == "Seattle")
{ name: c.name, age: c.age }
]
console.log('results=', results);
// results= [{"name":"Jim","age":36}]
ES6
Iterators
- Allows custom iteration
- Similar to a Java's java.lang.Iterable<T>
- Can be of a finite or infinite length
- Calculate as you go
Works in YAM+
Needs polyfill
Iterators
let fibonacci = {
[Symbol.iterator]() {
let pre = 0, cur = 1;
return {
next() {
[pre, cur] = [cur, pre + cur];
return {
done: cur > 100,
value: cur
};
}
}
}
}
var arr = []
for (var x of fibonacci) {
arr.push(x);
}
console.log(arr.join(', '));
// 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
ES6
Generators
- Simplify building iterators using
-
function*
-
yield
-
-
Important concepts: next, throw
Works in YAM+
Needs polyfill
Generators
let fibonacci = {
[Symbol.iterator]() {
let pre = 0, cur = 1;
return {
next() {
[pre, cur] = [cur, pre + cur];
return {
done: cur > 100,
value: cur
};
}
}
}
}
var arr = []
for (var x of fibonacci) {
arr.push(x);
}
console.log(arr.join(', '));
// 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
ES6
Collections
- Map
- Set
- Weak Map
- Weak Set
Map
- A simple key/value data structure
- Any value may be used as either a key or value
- Size can be retrieved easily
Works in YAM+
Needs polyfill
Map
var m = new Map([['a', 'b'], ['c', 'd']]);
m.size; // 2
m.forEach(function(key, value, map) {
...
});
m.get('a'); // 'b'
m.has('a'); // true
m.set('a', 14);
m.entries(); // MapIterator for key, value pairs
m.keys(); // MapIterator for keys
m.values(); // MapIterator for values
ES6
Set
- Stores a collection of unique values
- Can handle primitive values or object references equally well
- Uses ===
Works in YAM+
Needs polyfill
Set
var d = 'a';
var s = new Set(['a', 'b', 'c', d]);
s.size; // 3
s.has('A'.toLowerCase()); // true
ES6
WeakMap
- Keys must be Objects
- Keys may be garbage collected
Works in YAM+
Needs polyfill
WeakMap
var records = [
{id: 1, firstName: 'Walter', lastName: 'White'},
{id: 2, firstName: 'Jesse', lastName: 'Pinkman'}
];
var recordMetaData = new WeakMap(
records.map(
(r) => (
[r, {fullName: `${r.firstName} ${r.lastName}`}]
)
)
);
console.log(recordMetaData.get(records[0]).fullName);
// Walter White
console.log(recordMetaData.get(records[1]).fullName);
// Jesse Pinkman
ES6
WeakSet
- Just like Set, except that
- It holds weak references to members, so they can be garbage collected
- It's not iterable
- Keys must be Objects
Works in YAM+
Needs polyfill
Tips for ES6 Use
- Consider computational cost
- Remember our coding values
- Testability
- Maintainability
- Clarity
- Learn as much as you can!
Resources
- Transpiler: https://6to5.org/
- MDN: https://developer.mozilla.org
- ES6 Examples on Codepen: http://codepen.io/collection/nYywvW/
- ES6 Draft Specification: http://people.mozilla.org/~jorendorff/es6-draft.html
- ES6 Features overview: https://github.com/lukehoban/es6features#readme
Intro to ES6
By Mike North
Intro to ES6
- 912