Mike North, Principal Engineer, Yahoo Inc.
The JavaScript standard (ECMA-262)
Common Implementations
JavaScript JScript ActionScript
TC39 - Task group
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
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
let
A new keyword:
Conceptually similar to but defines a variable only within the current
var
Works in YAM+
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
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
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+
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
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
Pattern matching for objects and arrays, in assignment and function parameters
Works in YAM+
// 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
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
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
Allows specification of a default value for function parameters.
Works in YAM+
// 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
Works in YAM+
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
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
Works in YAM+
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
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
Works in YAM+
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
// 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
Works in YAM+
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
Works in YAM+
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
Works in YAM+
Needs polyfill
// 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
Works in YAM+
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
Works in YAM+
Needs polyfill
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
Works in YAM+
Needs polyfill
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
function*
yield
Important concepts: next, throw
Works in YAM+
Needs polyfill
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
Works in YAM+
Needs polyfill
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
Works in YAM+
Needs polyfill
var d = 'a';
var s = new Set(['a', 'b', 'c', d]);
s.size; // 3
s.has('A'.toLowerCase()); // true
ES6
Works in YAM+
Needs polyfill
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
Works in YAM+
Needs polyfill