Hi everyone.
I'm Craig,
and I like warm hugs!
Work in Wellington
Formerly worked on Touch
Now working on Preview/Tangram/Tractor
I ❤ JavaScript
& Frozen
Craig Spence's
Disney's
Frozen: JavaScript
or
JavaScript is better than people
The ECMAScript 2015 Spec Never Bothered Me Anyway
or
Big Summer Blow Out!
Win Prizes!
Answer Questions!
What are we
looking at?
Everything in the official ES2015 Spec (formerly known as ES6)
Some proposals from the ES2016 Spec (ES7)
A brief history
May 1995:
Brendan Eich creates JavaScript in 10 days
June 1997:
The ECMA*-262 spec is published (known as ECMAScript 1)
* European Computer Manufacturer Association
June 1998:
ECMAScript 2 is published!
December 1999:
ECMAScript 3 is published!
2000 - 2008...
December 2009:
ECMAScript 5!
June 2011:
ECMAScript 5.1!
Which brings us to...
ES2015!
DA FUQ?
What's new?
- arrows
- classes
- enhanced object literals
- template strings
- destructuring
- default + rest + spread
- let + const
- iterators + for ... of
- generators
- unicode
- modules
- map + set + weak map + weak set
- proxies
- symbols
- promises
- extended APIs
- binary + octal literals
- Reflect API
- tail calls
Arrows:
// ES5
Elsa.on('stress', function () {
// handle stress (badly);
});
['Anna', 'Hans', 'Sven'].map(function () {
// ...
});
fetch('https://icecastle/elsa')
.then(function (elsa) {
// Movie ends early...
})
.catch(function (error) {
// Drama ensues...
});
// ES2015
Elsa.on('stress', () => {
// handle stress (badly);
});
['Anna', 'Hans', 'Sven'].map(() => {
// ...
});
fetch('https://icecastle/elsa')
.then((elsa) => {
// Movie ends early...
})
.catch((error) => {
// Drama ensues...
});
Arrows:
// ES2015
this.on('stress', () => {
this.handleStressBadly;
});
['Anna', 'Hans'].map((character) => {
this.singWith(character);
});
fetch('https://icecastle/elsa')
.then((elsa) => {
this.movieEnds();
})
.catch((error) => {
this.moarDrama();
});
// ES5
let elsa = this;
elsa.on('stress', function () {
elsa.handleStressBadly;
});
['Anna', 'Hans'].map(function (character) {
this.singWith(character);
}, this);
fetch('https://icecastle/elsa')
.then(function (elsa) {
this.movieEnds();
}.bind(this))
.catch(function (error) {
this.moarDrama();
}.bind(this));
Arrows:
// Arrow functions can get even shorter! Note the missing parens
// around the parameters, and the missing braces around the body,
// and the implicit return for the first statement:
[1, 2, 3, 4].map(x => x * x); // [1, 4, 9, 16]
// Missing parens only works with single parameters though,
// otherwise you need them:
[1, 2, 3, 4].map((element, index) => element * index);
[1, 2, 3, 4].map(() => 1);
// Noop in ES5:
function () { }
// Noop in ES2015:
() => {}
// Constant function in ES5:
function () {
return 1;
}
// Constant function in ES2015:
() => 1
Classes:
// ES5
function Snowman (name) {
this.name = name;
}
Snowman.prototype.sayHi = function () {
return 'Hi everyone! I\'m'
+ this.name;
};
function Olaf () {
Snowman.call(this, 'Olaf');
}
Olaf.prototype = Object.create(Snowman.prototype);
Olaf.prototype.sayHi = function sayHi() {
return Snowman.prototype.sayHi.call(this)
+ ', and I like warm hugs';
};
var olaf = new Olaf();
olaf.sayHi();
// ES2015
class Snowman {
constructor (name) {
this.name = name;
}
sayHi () {
return `Hi everyone. I'm ${this.name}`
}
}
class Olaf extends Snowman {
constructor () {
super('Olaf');
}
sayHi () {
return `${super.sayHi()} and I like warm hugs!`
}
}
let olaf = new Olaf;
olaf.sayHi();
Classes:
// ES5
function Snowman (name) {
this._name = name;
Object.defineProperty(this, 'name', {
get: function () {
return this._name;
},
set: function (newName) {
this._name = newName;
}
});
}
// ES2015
class Snowman {
constructor (name) {
this._name = name;
}
get name () {
return this._name;
}
set name (newName) {
this._name = newName;
}
}
Yoohoo, Question 1!
The value of this inside an arrow function is bound to the this value outside of that arrow function.
true || false:
Object literals:
// ES5
var isBetterThanPeople = true;
var reindeer = getReindeer();
var reindeerOptions = {
isBetterThanPeople: isBetterThanPeople
};
reindeerOptions[reindeer.name] = reindeer;
// ES2015
let isBetterThanPeople = true;
let reindeer = getReindeer();
let reindeerOptions = {
isBetterThanPeople,
[reindeer.name]: reindeer
};
Template strings:
// ES5
var bestLyrics = '\n\
And it\'s nothing like I\'ve ever known before!\n\
Love is an open door!';
function finish (x) {
return 'We finish eat other\'s ' + x;
}
finish('sandwiches');
// ES2015
let bestLyrics = `
And it's nothing like I've ever known before!
Love is an open door!
`;
function finish (x) {
return `We finish eat other's ${x}`;
}
finish('sandwiches');
Destructuring:
// ES5
var princesses = ['Elsa', 'Anna'];
var heirToArendelle = princesses[0];
// or
var heirToArendelle = _.first(princesses);
// ES2015
let princesses = ['Elsa', 'Anna'];
let [heirToArendelle] = princesses;
Destructuring:
// ES5
var frozenFacts = {
producer: {
firstName: 'Peter',
lastName: 'Del Vecho'
},
runningTime: '102'
};
var producer = frozenFacts.producer;
var firstName = producer.firstName;
var length = frozenFacts.runningTime;
// ReferenceError:
var directorName = frozenFacts.director.name;
// ES2015
let frozenFacts = {
producer: {
firstName: 'Peter',
lastName: 'Del Vecho'
},
runningTime: '102'
};
let {
producer: { firstName },
runningTime: length
} = frozenFacts;
// No error!
let { director: { name }} = frozenFacts;
// name === undefined
Yoohoo, Question 2!
true || false:
Trying to destructure a value out from a property that does not exist on an object will throw an error.
default + rest + spread:
// ES5
function build (what) {
what = what || 'snowman';
return what;
}
build(); // 'snowman'
// ES2015
function build (what = 'snowman') {
return what;
}
build(); // 'snowman'
default + rest + spread:
// ES5
function sweetChoreography (arguments) {
var guests = Array.prototype.slice.apply(arguments);
guests.forEach(function (guest) {
danceWith(guest);
});
}
sweetChoreography('Hans', 'Duke of Wesselton', 'Trolls');
// ES2015
function sweetChoreography (...guests) {
guests.forEach(guest => danceWith(guest));
}
sweetChoreography('Hans', 'Duke of Wesselton', 'Trolls');
let + const:
// ES5
// Variable declarations:
var itGo = '';
// Constants:
var BOTHERED_BY_COLD = false;
// ES2015
// Variable declarations:
let itGo = '';
// Constants:
const BOTHERED_BY_COLD = false;
let + const:
// ES5
for (var i = 0; i < 10; i += 1) {
element.click(function () {
console.log(i);
});
}
// 9, 9, 9, 9, 9, 9, 9, 9, 9, 9
// ES2015
for (let i = 0; i < 10; i += 1) {
element.click(function () {
console.log(i);
});
}
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
let + const:
// ES2015
const ARENDELLE = {
ruler: 'Elsa'
};
// Doesn't throw error:
ARENDELLE.ruler = 'Hans';
// const objects are not immutable:
const ARENDELLE = Object.freeze({
ruler: 'Elsa'
});
// Now throws:
ARENDELLE.ruler = 'Hans';
Yoohoo, Question 3!
Objects that are created using const are immutable
true || false:
modules:
// ES5 (commonjs style)
// frozen.js:
module.exports = function frozen () {
console.log('best movie evah!!!');
}
module.exports.yay = [
'Anna',
'Elsa',
'Kristoff',
'Olaf'
];
// myapp.js
var frozen = require('frozen');
yay = frozen.yay;
frozen();
console.log(yay);
// ES2015
// frozen.js:
export default function frozen () {
console.log('best movie evah!!!');
}
export const yay = [
'Anna',
'Elsa',
'Kristoff',
'Olaf'
];
// myapp.js
import frozen, { yay } from 'frozen';
frozen();
symbols:
// ES2015
// elsa.js
let conceal = Symbol();
class Elsa {
constructor (feelings) {
this[conceal] = feelings;
}
}
const feelings = 'BIG FEELS';
export default const elsa = new Elsa(feelings);
// app.js
import elsa from 'elsa';
// No way to access feelings (except reflection magic)
symbols:
// ES2015:
// Special symbols:
NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
promises:
// ES2015:
fetch('https://icecastle/elsa')
.then(elsa => {
// Movie ends early...
})
.catch(error => {
// Drama ensues...
});
Extended APIs:
// ES2015:
Number.EPSILON
Number.isInteger(Infinity) // false
Number.isNaN('NaN') // false
Math.acosh(3) // 1.762747174039086
Math.hypot(3, 4) // 5
Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2) // 2
'abcde'.includes('cd') // true
'let it go'.repeat(2) // 'let it go let it go'
Array.from(document.querySelectorAll('*')) // Returns a real Array
Array.of(1, 2, 3) // Similar to new Array(...), but without special one-arg behavior
[0, 0, 0].fill(7, 1) // [0,7,7]
[1, 2, 3].find(x => x == 3) // 3
[1, 2, 3].findIndex(x => x == 2) // 1
[1, 2, 3, 4, 5].copyWithin(3, 0) // [1, 2, 3, 1, 2]
['a', 'b', 'c'].entries() // iterator [0, 'a'], [1, 'b'], [2, 'c']
['a', 'b', 'c'].keys() // iterator 0, 1, 2
['a', 'b', 'c'].values() // iterator 'a', 'b', 'c'
Object.assign(Point, { origin: new Point(0,0) })
Yoohoo, Question 4!
true || false:
Values assigned with symbols are completely private to their scope.
ES2016?!
Array.prototype.includes
async/await
exponentiation operator
SIMD
decorators
observables
pipe operator
Using ES2015+ today
Pretty good support in browsers (see kangax tables)
Pretty good support in node
Excellent support using
transpilers/polyfills
(TypeScript or Babel, with core.js)
Questions?
The ES2015 Spec Never Bothered Me Anyway
By Craig Spence
The ES2015 Spec Never Bothered Me Anyway
- 3,942