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,413