Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ES6

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

 ES6

The talk I gave at the July MancJS on ES6 and some of its primary features.

Avatar for Martin Rue

Martin Rue

July 01, 2015

Other Decks in Programming

Transcript

  1. History • JavaScript was created by Brendan Eich. The result

    of 10 days of work. • We’ve all been stuck with a perpetual 10 day old crying baby for the last 20 years.
  2. Better History • Following the 1995 Netscape release of JavaScript,

    Microsoft did a “me too” in 1996 with JScript. • We all loved Microsoft for it. • Netscape then moved JavaScript to Ecma for standardisation, creating the ECMA-262 spec.
  3. Better History • Since the first spec, there have been

    4 more major editions. • Version 3 added try/catch, regex, etc. • Version 4 was eventually abandoned due to arguments over acceptable levels of language complexity. • Version 5 came in 2009, adding ‘strict’ mode, getter/setters, JSON, some reflection APIs.
  4. Better History • And in June 2015, version 6 was

    completed. • ES6 brings more new features, syntax and changes than any previous version. • If this is all a bit much, you’ll be glad to know work is already underway on version 7. • Stop crying.
  5. What about JavaScript? • ECMAScript is the standard. • JavaScript

    is the implementation. • JavaScript is the only one we really care about (but there’s also JScript and ActionScript to keep the masochists happy).
  6. So, what’s new? • Block Scoping • Let / Const

    • Arrow Syntax • Symbols • Destructuring • Classes • Proxies • Modules • Much more (Reflection, Promises, Generators, Map, Set, etc.) Research others: MDN.
  7. Block Scoping • Until ES6, we had just two primary

    scopes: global and function. • To create a new scope, you would need a new function. • ES6 now finally adds support for block scoping via the let and const keywords. The var keyword still works as before.
  8. Block Scoping { var message = 'hello world'; console.log(message); }

    console.log(message); // hello world // hello world message is not scoped to the block, but the outer scope
  9. Block Scoping { let message = 'hello world'; console.log(message); }

    console.log(message); // hello world // ReferenceError: message is not defined now message is scoped to the block only
  10. Let / Const • Two new keywords for variable declarations.

    • let is like var, but block-scoped and not hoisted. • const creates read-only constants, and is also not hoisted.
  11. Let / Const console.log(eventName); var eventName = 'MancJS'; // undefined

    undefined because the var was hoisted before it was assigned
  12. Let / Const console.log(eventName); const eventName = 'MancJS'; // ReferenceError:

    eventName is not defined - temporal dead zone no longer hoisted, so it doesn’t exist
  13. Let / Const • This is know as the TDZ

    – Temporal Dead Zone • In ES5, this wasn’t possible. A global or var was always hoisted. • With let and const, the identifier exists only once it’s declared and is nonexistent until then (which is the TDZ). Even typeof will now throw in the TDZ.
  14. Arrow Syntax • Shorthand for creating functions. • Makes code

    shorter and a bit nicer to read. • Preserves lexical scope from parent. 3rd point: meaning this acts more sanely 3rd point: meaning there’s now ANOTHER way for this to be bound
  15. Arrow Syntax var square = function(number) { return number *

    number; }; const square = (number) => { return number * number; }; function keyword disappears const because, it turns out most things don’t need to change
  16. Arrow Syntax var square = function(number) { return number *

    number; }; const square = number => number * number; on the same line we can drop braces and return, implicit return
  17. Arrow Syntax var square = function(number) { return number *

    number; }; const square = n => n * n; shorten variables names
  18. Arrow Syntax [1, 2, 3, 4].map(n => n * n);

    // [ 1, 4, 9, 16 ] [1, 2, 3, 4].reduce((n, m) => n + m); // 10
  19. Arrow Syntax var user = { name: 'Martin', print: function()

    { var getWithPrefix = function(prefix) { return prefix + ' ' + this.name; }; console.log('Name is ' + getWithPrefix('Mr')); } }; user.print(); what’s the output?
  20. Arrow Syntax var user = { name: 'Martin', print: function()

    { var getWithPrefix = function(prefix) { return prefix + ' ' + this.name; }; console.log('Name is ' + getWithPrefix('Mr')); } }; user.print(); // TypeError: Cannot read property 'name' of undefined inner function this is not bound, set to undefined
  21. Arrow Syntax var user = { name: 'Martin', print: function()

    { var getWithPrefix = prefix => { return prefix + ' ' + this.name; }; console.log('Name is ' + getWithPrefix('Mr')); } }; user.print(); // Name is Mr Martin fat arrow captures lexical scope
  22. Arrow Syntax var user = { name: 'Martin', print: function()

    { var getWithPrefix = prefix => prefix + ' ' + this.name; console.log('Name is ' + getWithPrefix('Mr')); } }; user.print(); // Name is Mr Martin again, shorten the syntax to make it cleaner
  23. Symbols • A new primitive type. • A new way

    to add properties to objects (separate from string keys). • Not visible as object keys, but also not private. • There’s a set of well-known symbols we can use to override language behaviour that was previously impossible.
  24. Symbols const s1 = Symbol(); const s2 = Symbol('Symbol 2');

    const s3 = Symbol('Symbol 3'); console.log(s1, s2, s3); console.log(typeof s1, typeof s2, typeof s3); what’s the output?
  25. Symbols const s1 = Symbol(); const s2 = Symbol('Symbol 2');

    const s3 = Symbol('Symbol 3'); console.log(s1, s2, s3); // Symbol() Symbol(Symbol 2) Symbol(Symbol 3) console.log(typeof s1, typeof s2, typeof s3); // symbol symbol symbol
  26. Symbols var password = Symbol('Password'); var data = { name:

    'MancJS', kind: 'event', [password]: 'abcd' }; console.log(data.name); console.log(data.password); embed the symbol in an object with [] syntax
  27. Symbols var password = Symbol('Password'); var data = { name:

    'MancJS', kind: 'event', [password]: 'abcd' }; console.log(data.name); console.log(data.password); // MancJS // undefined
  28. Symbols var password = Symbol('Password'); var data = { name:

    'MancJS', kind: 'event', [password]: 'abcd' }; console.log(data.name); console.log(data[password]); // MancJS // abcd using symbol we can access the value stored
  29. Symbols var password = Symbol('Password'); var data = { name:

    'MancJS', kind: 'event', [password]: 'abcd' }; console.log(Object.keys(data)); // [ 'name', 'kind' ] console.log(Object.getOwnPropertyNames(data)); // [ 'name', 'kind' ] console.log(Object.getOwnPropertySymbols(data)); // [ Symbol(Password) ] symbols don’t show up as object keys can be found with getOwnPropertySymbols
  30. Symbols: for..of const numbers = [1, 2, 3, 4, 5];

    for (let number of numbers) { console.log(number); } // 1, 2, 3, 4, 5 for..of loop which use iterators underneath no more accidental array indexes instead of values
  31. Symbols: for..of const numbers = { [Symbol.iterator]() { let current

    = 1; return { next() { return { done: current > 5, value: current++ }; } }; } }; for (let number of numbers) { console.log(number); } // 1, 2, 3, 4, 5 implement your own iterator with Symbol.iterator
  32. Destructuring • A new syntax for extracting values from objects

    and arrays. • Can make code more readable. • Makes returning multiple values much nicer. • Supports syntax for ‘rest’ values and ignoring values.
  33. Destructuring: Arrays const numbers = [1, 2, 3, 4, 5];

    let [first, second] = numbers; console.log(first); // 1 console.log(second); // 2 grab first two values
  34. Destructuring: Arrays const numbers = [1, 2, 3, 4, 5];

    let [first, , , , last] = numbers; console.log(first); // 1 console.log(last); // 5 ignoring values possible
  35. Destructuring: Arrays const numbers = [1, 2, 3, 4, 5];

    let [first, second, ...everythingElse] = numbers; console.log(first); // 1 console.log(second); // 2 console.log(everythingElse); // [ 3, 4, 5 ] can use the rest syntax to capture everything else
  36. Destructuring: Arrays function doSomething() { return [null, 42]; } let

    [err, result] = doSomething(); makes multiple return values nicer to deal with
  37. Destructuring: Objects let object = { name: 'MancJS', age: 2.5

    }; let { age, name } = object; console.log(name, age); // MancJS 2.5 order of object keys not important
  38. Destructuring: Objects let object = { name: 'MancJS', age: 2.5

    }; let { name: n, age: a } = object; console.log(n, a); // MancJS 2.5 can rename properties with the colon
  39. Destructuring: Objects let meetup = { name: 'MancJS', age: 2.5,

    location: 'Manchester', tags: ['js', 'manc'] }; function display({name, location}) { console.log(`${name} is held in ${location}`); } display(meetup); // MancJS is held in Manchester can use destructuring syntax inside parameters to capture only the object keys you want
  40. Classes • A simple sugar over prototype pattern for creating

    class-like objects with class keyword. • Adds OO-like concepts: constructors, inheritance, static methods, getters, setters. • Like let and const, class is not hoisted and can therefore create TDZs.
  41. Classes: Old function Dog(name) { this.name = name; } Dog.prototype.toString

    = function() { return `Dog named ${this.name}`; }; var toto = new Dog('Toto'); console.log(typeof Dog); // function console.log(typeof toto); // object console.log(toto.toString()); // Dog named Toto original method
  42. Classes: New class Dog { constructor(name) { this.name = name;

    } toString() { return `Dog named ${this.name}`; } } var toto = new Dog('Toto'); console.log(typeof Dog); // function console.log(typeof toto); // object console.log(toto.toString()); // Dog named Toto notice new object literal syntax, not repeating keys
  43. Classes: Extends class Animal { constructor(name) { this.name = name;

    } } class Dog extends Animal { constructor(name) { super(name); } toString() { return `Dog named ${this.name}`; } } var toto = new Dog('Toto'); console.log(toto.toString()); // Dog named Toto supports inheritance
  44. Classes: Getters & Setters class Dog { set name(name) {

    this.dogName = `Dog: ${name}`; } get name() { return this.dogName; } } var toto = new Dog(); toto.name = 'Toto'; console.log(toto.name); // Dog: Toto can have getters and setters
  45. Proxy • New built-in type Proxy, takes a target and

    a handler. • Can be used to intercept operations on a target and perform additional things before forwarding. • Can capture all kinds of operations: get, set, apply, deleteProperty, construct, enumerate. • Useful for logging, validation, interception.
  46. Proxy let handler = { get(receiver, name) { return `Thing

    you tried to read: ${name}`; } }; let p = new Proxy({}, handler); console.log(p.something); // Thing you tried to read: something handler intercepts reads against the target
  47. Proxy let target = {}; let logger = { set(obj,

    prop, value) { console.log(`Caller set ${prop} to ${value}`); obj[prop] = value; } }; let p = new Proxy(target, logger); p.name = 'MancJS'; // Caller set name to MancJS console.log(target.name); // MancJS here capturing setting of property still needs to set value now visible on target
  48. Modules • Finally a native solution to creating components in

    JavaScript. • Introduces import, export, from keywords to define and consume modules. • A host-based loader determines how modules are loaded at runtime. Can be configured to do different things. • Allows named, namespaced and default imports.
  49. Modules: Old // module.js function someFunction1() { } function someFunction2()

    { } module.exports = { someFunction1: someFunction1, someFunction2: someFunction2 }; // app.js var myModule = require('./module'); myModule.someFunction1(); myModule.someFunction2(); CommonJS
  50. Modules: Named // module.js export function someFunction1() { console.log('1'); }

    export function someFunction2() { console.log('2'); } // app.js import {someFunction1} from './module'; someFunction1(); export goes at the start of the name can export variables too
  51. Modules: Namespaced // module.js export function someFunction1() { console.log('1'); }

    export function someFunction2() { console.log('2'); } // app.js import * as myModule from './module'; myModule.someFunction1(); myModule.someFunction2(); Most like CommonJS style of capturing everything into a single object
  52. Modules: Default // user.js export default class User { constructor(name)

    { this.name = name; } toString() { return `User with name: ${this.name}`; } } // app.js import SystemUser from './user'; const me = new SystemUser('Martin'); console.log(me.toString()); // User with name: Martin name doesn’t need to match the export, as it knows because it’s default note the literal syntax again
  53. Extras: Default Parameters function add(number1, number2 = 42) { return

    number1 + number2; } add(10); // 52 add(10, 20); // 30
  54. Extras: Spread function add(param1, param2, ...others) { console.log(param1, param2, others);

    } add(1, 2, 3, 4, 5); // 1 2 [ 3, 4, 5 ] can capture remaining arguments could capture all this way instead of ‘arguments’ – is real array
  55. Extras: Spread const todaysScores = [42, 43]; const yesterdaysScores =

    [30, 40]; const allScores = [...todaysScores, ...yesterdaysScores]; console.log(allScores); // [ 42, 43, 30, 40 ] flatten arrays
  56. Extras: Spread const todaysScores = [42, 43]; const yesterdaysScores =

    [30, 40]; const allScores = [...todaysScores, ...yesterdaysScores]; function add(n1, n2, n3, n4) { return n1 + n2 + n3 + n4; } const total = add(...allScores); console.log(total); // 155 useful for expanding array into function arguments
  57. ES7 • Work already underway. • Completion expected around mid-2016.

    • Currently proposals for class properties, decorators, async functions. • Some transpilers experimentally support ES7 proposals already.
  58. ES7: Async function wait(seconds, callback) { setTimeout(callback, seconds * 1000);

    } wait(5, function() { console.log('done'); }); old school way
  59. ES7: Async function wait(seconds, callback) { setTimeout(callback, seconds * 1000);

    } wait(2.5, function() { wait(2.5, function() { console.log('done'); }); }); problem: nesting
  60. ES7: Async function wait(seconds) { return new Promise(resolve => {

    setTimeout(resolve, seconds * 1000); }); } wait(2.5).then(() => { return wait(2.5); }).then(() => { console.log('done'); }); ES6 native promises
  61. ES7: Async function wait(seconds) { return new Promise(resolve => {

    setTimeout(resolve, seconds * 1000); }); } Promise.all([wait(2.5), wait(2.5)]).then(() => { console.log('done'); }); could switch to all instead, but not the same, why?
  62. ES7: Async function wait(seconds) { return new Promise(resolve => {

    setTimeout(resolve, seconds * 1000); }); } [2.5, 2.5].reduce((p, time) => { return p.then(() => wait(time)); }, Promise.resolve()).then(() => { console.log('done'); }); reduce pattern is used, but ugly
  63. ES7: Async async function wait(seconds) { return new Promise(resolve =>

    { setTimeout(resolve, seconds * 1000); }); } await wait(2.5); await wait(2.5); console.log('done'); ES7 marks the function async can await, just like sync code was possible with generators in ES6 + flow libraries
  64. ES7: Async async function wait(seconds) { return new Promise(resolve =>

    { setTimeout(resolve, seconds * 1000); }); } await* [wait(2.5), wait(2.5)]; console.log('done'); can await on multiple values in parallel