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

ECMAScript 6/2015

ECMAScript 6/2015

Show features of ECMAScript 2015 with examples, most from babeljs.io.
Hints for usage with Node.js, webpack, React and a link to the implementation status in different browsers.

Anton Wilhelm

December 14, 2015
Tweet

More Decks by Anton Wilhelm

Other Decks in Technology

Transcript

  1. Version published info 1 1997 / 06 first version 2

    1998 / 06 ISO/IEC 16262 3 1999 / 12 regex, try/catch, … 4 canceled disagreement, too complex drafts 5 2009 / 12 strict mode, get/set, 
 JSON become popular 5.1 2011 / 06 ISO/IEC 16262:2011, Version 3 2015 2015 / 06 Codename: Harmony, ECMAScript 6 2016 in progress ECMAScript 7, async/await, Object.observe, nested destructing ECMAScript History
  2. Feature Overview - Map + Set + WeakMap + WeakSet

    - Proxies - Symbols - Subclassable Built-ins - Math + Number + String + Object APIs - Binary and Octal Literals - Promises - Reflect API - Tail Calls - Arrows and Lexical This - Classes - Enhanced Object Literals - Template Strings - Destructuring - Default + Rest + Spread - Let + Const - Iterators + For..Of - Generators - Unicode - Modules
  3. Not Part of ES 2015 but still awesome - Module

    Loaders - Dynamic loading - State isolation - Global namespace isolation - Compilation hooks - Nested virtualization - JSX - JavaScript + HTML
 without escaping HTML syntax echo "<script language='javascript'>\n"; echo " location.href=\"${_SERVER['SCRIPT_NAME']}?${_SERVER['QUERY_STRING']}" . "&width=\" + screen.width + \"&height=\" + screen.height;\n"; echo "</script>\n";
  4. Arrows and Lexical This var odds = evens.map(v => v

    + 1) // impicit return var nums = evens.map((v, i) => v + i) // impicit return nums.forEach(v => { if (v % 5 === 0) fives.push(v); }) // no impicit return var bob = { _name: "Bob", _friends: [], printFriends() { this._friends.forEach(f => console.log(this._name + " knows " + f)); } }
  5. Arrows and Lexical This var odds = evens.map(v => v

    + 1) // impicit return var nums = evens.map((v, i) => v + i) // impicit return nums.forEach(v => { if (v % 5 === 0) fives.push(v); }) // no impicit return var bob = { _name: "Bob", _friends: [], printFriends() { this._friends.forEach(f => console.log(this._name + " knows " + f)); } }
  6. Classes class Foo extends Bar { constructor(a, b, c) {

    super(a, b) this.c = c this.d = Foo.defaultValue() } update(x) { super.update() } static defaultValue() { return new Utils.create() } }
  7. Enhanced Object Literals var obj = { // __proto__ __proto__:

    theProtoObj, // Shorthand for handler: handler’ handler, // Methods toString() { // Super calls return "d " + super.toString() }, // Computed (dynamic) property names [ "prop_" + (() => 42)() ]: 42 }
  8. Template Strings // Basic literal string creation `This is a

    pretty little template string.` // Multiline strings `In ES5 this is not legal.` // Interpolate variable bindings var name = "Bob", time = "today"; `Hello ${name}, how are you ${time}?` // Unescaped template strings String.raw`In ES5 "\n" is a line-feed.`
  9. Destructuring // list matching var [a, ,b] = [1,2,3] a

    === 1 b === 3 // object matching var { op: a, lhs: { op: b }, rhs: c } = getNode() // Fail-soft destructuring var [a] = [] a === undefined // Fail-soft destructuring with defaults var [a = 1] = [] a === 1 var _getASTNode = getNode(); var a = _getASTNode.op; var b = _getASTNode.lhs.op; var c = _getASTNode.rhs; ES 5
  10. Nested Destructuring = fail-hard var { op: a, lhs: {

    op: b }, rhs: c } = {} // TypeError: Cannot read property 'op' of undefined
  11. fail-soft with loadash var source = {} var a =_.get(source,

    'ops') var b1 = _.get(source, 'lhs.op') var b2 = _.get(source, ['lhs', 'op']) var c =_.get(source, 'hrs') _.get(source, 'really.deep[2]["and-dynamic"]')
  12. Default + Rest + Spread function f(x, y=12) { //

    y is 12 if not passed (or passed as undefined) return x + y; } f(3) == 15 function f(x, ...y) { // y is an Array return x * y.length; } f(3, "hello", true) == 6 function f(x, y, z) { return x + y + z; } // Pass each elem of array as argument f(...[1,2,3]) == 6
  13. Let + Const function f() { { let x; {

    // okay, block scoped name const x = "sneaky"; // error, const x = "foo"; } // okay, declared with `let` x = "bar"; // error, already declared in block let x = "inner"; } }
  14. Iterators + For..Of let fibonacci = { [Symbol.iterator]() { let

    pre = 0, cur = 1; return { next() { [pre, cur] = [cur, pre + cur]; return { done: false, value: cur } } } } } for (var n of fibonacci) { // truncate the sequence at 1000 if (n > 1000) break; console.log(n); }
  15. Generators var fibonacci = { [Symbol.iterator]: function*() { var pre

    = 0, cur = 1; for (;;) { var temp = pre; pre = cur; cur += temp; yield cur; } } } for (var n of fibonacci) { // truncate the sequence at 1000 if (n > 1000) break; console.log(n); }
  16. Generators var fibonacci = { [Symbol.iterator]: function*() { var pre

    = 0, cur = 1; for (;;) { var temp = pre; pre = cur; cur += temp; yield cur; } } } for (var n of fibonacci) { // truncate the sequence at 1000 if (n > 1000) break; console.log(n); }
  17. Generators + async/wait var fibonacci = { [Symbol.iterator]: async function()

    { var pre = 0, cur = 1; for (;;) { var temp = pre; pre = cur; cur += temp; await cur; } } } for (var n of fibonacci) { // truncate the sequence at 1000 if (n > 1000) break; console.log(n); }
  18. Unicode // same as ES5.1 "㖊".length == 2 // new

    RegExp behaviour, opt-in u’ "㖊".match(/./u)[0].length == 2 // new form "\u{20BB7}" == "㖊" == "\uD842\uDFB7" "".match(/\u{1d306}/u)[0].length === 2 // same as ES5.1 "㖊".length == 2; // new RegExp behaviour, opt-in u’ "㖊".match(/(?:[\0-\t\x0B\f\x0E-\u2027\u202A-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?! [\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/)[0].length == 2; // new form "㖊" == "㖊" == "㖊"; "".match(/(?:\uD834\uDF06)/)[0].length === 2;
  19. Modules // lib/math.js export function sum(x, y) { return x

    + y } export var pi = 3.141593 // app.js import * as math from "lib/math" alert("2π = " + math.sum(math.pi, math.pi)) // otherApp.js import {sum, pi} from "lib/math" module.exports.foo = foo = function(x) { return double(x); } module.exports.double = double = function(y) { return y * 2; } ES 5
  20. Modules // lib/mathplusplus.js export * from "lib/math" export var e

    = 2.71828182846 export default function(x) { return Math.exp(x) } // app.js import exp, {pi, e} from "lib/mathplusplus"
  21. load non-ES modules // lib/mathplusplus.js import * as _ from

    "lodash" const App = require("./app.coffee")
  22. Map + Set + WeakMap + WeakSet // Sets var

    s = new Set() s.add("hello").add("goodbye").add("hello") s.size === 2 s.has("hello") === true // Maps var m = new Map() m.set("hello", 42) m.set(s, 34) m.get(s) == 34 // Weak Maps var wm = new WeakMap() wm.set(s, { extra: 42 }) wm.size === undefined // Weak Sets var ws = new WeakSet() ws.add({ data: 42 }) // Because the added object has no other references, // it will not be held in the set
  23. Proxies // Proxying a normal object var target = {}

    var handler = { get: function (receiver, name) { return `Hello, ${name}!` } } var p = new Proxy(target, handler) p.world === "Hello, world!“
  24. Symbols Symbol("foo") !== Symbol("foo") const foo = Symbol() const bar

    = Symbol() typeof foo === "symbol" typeof bar === "symbol" let obj = {} obj[foo] = "foo" obj[bar] = "bar" JSON.stringify(obj) // {} Object.keys(obj) // [] Object.getOwnPropertyNames(obj) // [] Object.getOwnPropertySymbols(obj) // [ foo, bar ] A symbol is a unique and immutable data type and may be used as an identifier for object properties. The symbol object is an implicit object wrapper for the symbol primitive data type.
  25. Symbols Symbol.for("app.foo") === Symbol.for("app.foo") const foo = Symbol.for("app.foo") const bar

    = Symbol.for("app.bar") Symbol.keyFor(foo) === "app.foo" Symbol.keyFor(bar) === "app.bar" The Symbol.for(key) method searches for existing symbols in a runtime-wide symbol registry with the given key and returns it if found. Otherwise a new symbol gets created in the global symbol registry with this key.
  26. Symbols var MyClass = (function() { // module scoped symbol

    var key = Symbol("key") function MyClass(privateData) { this[key] = privateData } MyClass.prototype = { doStuff: function() { return this[key] + 1 } }; return MyClass })() var m = new MyClass('foo') m["key"] === undefined JSON.stringify(m) // '{}' console.log(m) // {} Object.keys(m) // [] Object.getOwnPropertySymbols(m) // [ Symbol(key) ]
  27. Reflect API var O = {a: 1} Object.defineProperty(O, 'b', {value:

    2}) O[Symbol('c')] = 3 Reflect.ownKeys(O) // ['a', 'b', Symbol(c)] function C(a, b){ this.c = a + b } var instance = Reflect.construct(C, [20, 22]) instance.c // 42
  28. Tail Calls function factorial(n, acc = 1) { "use strict"

    if (n <= 1) return acc return factorial(n - 1, n * acc) } factorial(100000) // RangeError: Maximum call stack size exceeded function factorial(_x2) { var _arguments = arguments; var _again = true; _function: while (_again) { var n = _x2; "use strict"; _again = false; var acc = _arguments.length <= 1 || _arguments[1] === undefined ? 1 : _arguments[1]; if (n <= 1) return acc; _arguments = [_x2 = n - 1, n * acc]; _again = true; acc = undefined; continue _function; } } factorial(100000); // Infinity :)
  29. // Dynamic loading – System’ is default loader System.import("lib/math").then(function(m) {

    alert("2π = " + m.sum(m.pi, m.pi)) }); // Create execution sandboxes – new Loaders var loader = new Loader({ global: fixup(window) // replace console.log’ }) loader.eval("console.log(\"hello world!\");") // Directly manipulate module cache System.get("jquery") System.set("jquery", Module({$: $})) // WARNING: not yet finalized
  30. JSX

  31. CoffeeScript + r-dom render: -> r.div [ r.form className: 'addMemberForm'

    onSubmit: @props.handleSubmit @_handleSubmit [ r Row, {className: 'singleline'}, [ r TextInput, key: '1' inputProps: _.extend {}, @props.fields.emailInput, placeholder: @props.i18n.t 'email_input' labelProps: errorMessage: @props.i18n.t @props.fields.emailInput.error r Button, key: '2' icon: 'plus' className: 'add' ] ] ]
  32. JSX render() { const { handleSubmit, fields, i18n } =

    this.props return( <div> <form className='addMemberForm' onSubmit={handleSubmit(this._handleSubmit)} > <Row className='singleline'> <TextInput key='1' inputProps={Object.assign( {}, fields.emailInput, {placeholder: i18n.t('email_input')} )} labelProps={{ errorMessage: i18n.t(fields.emailInput.error) }}> </TextInput> <Button key='2' icon='plus' className='add'/> </Row> </form> </div> ) }
  33. JSX bind context render() { const { handleSubmit, fields, i18n

    } = this.props return( <div> <form className='addMemberForm' onSubmit={() => {handleSubmit(this._handleSubmit)}} > <Row className='singleline'> <TextInput key='1' inputProps={Object.assign( {}, fields.emailInput, {placeholder: i18n.t('email_input')} )} labelProps={{ errorMessage: i18n.t(fields.emailInput.error) }}> </TextInput> <Button key='2' icon='plus' className='add'/> </Row> </form> </div> ) }
  34. JSX bind context ES7 render() { const { handleSubmit, fields,

    i18n } = this.props return( <div> <form className='addMemberForm' onSubmit={handleSubmit(::this._handleSubmit)} > <Row className='singleline'> <TextInput key='1' inputProps={Object.assign( {}, fields.emailInput, {placeholder: i18n.t('email_input')} )} labelProps={{ errorMessage: i18n.t(fields.emailInput.error) }}> </TextInput> <Button key='2' icon='plus' className='add'/> </Row> </form> </div> ) }
  35. Optimisation proper tail calls (tail call optimisation) Syntax default function

    parameters rest parameters spread (...) operator object literal extensions for..of loops octal and binary literals template strings RegExp "y" and "u" flags destructuring, declarations destructuring, assignment destructuring, parameters Unicode code point escapes new.target Bindings const let Functions arrow functions class super generators Built-ins typed arrays Map Set WeakMap WeakSet Proxy Reflect Promise Symbol well-known symbols[17] Built-in extensions Object static methods function "name" property String static methods String.prototype methods RegExp.prototype properties Array static methods Array.prototype methods Number properties Math methods Subclassing Array is subclassable RegExp is subclassable Function is subclassable Promise is subclassable miscellaneous subclassables Misc prototype of bound functions Proxy, internal 'get' calls Proxy, internal 'set' calls Proxy, internal 'defineProperty' calls Proxy, internal 'deleteProperty' calls Proxy, internal 'getOwnPropertyDescriptor' calls Proxy, internal 'ownKeys' calls Object static methods accept primitives own property order miscellaneous Annex b non-strict function semantics[25] __proto__ in object literals[26] Object.prototype.__proto__ String.prototype HTML methods RegExp syntax extensions 59 features and 627 test cases
  36. All shipping features, which V8 considers stable, are turned on

    by default on Node.js and do NOT require any kind of runtime flag. In progress features can be activated individually by their respective harmony flag 
 (e.g. --harmony_destructuring), although this is highly discouraged unless for testing purposes. node --v8-options | grep harmony
  37. - Transpiler - Configuration via Plugins - ES2015 features can

    be enabled individually - or with presets - or other Plugins, non ES2015, JSX, custom Plugins - Polyfill (regenerator runtime + core-js)
  38. Feature Overview - Map + Set + WeakMap + WeakSet

    P - Proxies X - Symbols P* - Subclassable Built-ins TP* - Math + Number + String + Object APIs P* - Binary and Octal Literals T* - Promises P* - Reflect API P* - Tail Calls T* - Arrows and Lexical This T - Classes T - Enhanced Object Literals T - Template Strings T - Destructuring T - Default + Rest + Spread T - Let + Const T - Iterators + For..Of TP - Generators TP - Unicode T - Modules T T = Transpiler P = Polyfill X = not supported at all * = limited / partial support
  39. { "presets": ["react", "es2015"], "env": { "development": { "plugins": [

    ["react-transform", { "transforms": [{ "transform": "react-transform-hmr", "imports": ["react"], "locals": ["module"] }, { "transform": "react-transform-catch-errors", "imports": ["react", "redbox-react"] }] }] ] } } } .babelrc { plugins: [ new webpack.HotModuleReplacementPlugin(), ], module: { loaders: [{ test: /\.js$/, loaders: ['babel'], include: path.join(__dirname, 'src') }] } } webpack-config.js