1.69k likes | 3.18k Views
ECMAScript 6. Luke Hoban git.io/es6features. ECMAScript History. ECMAScript 6. ES6 More significant changes than ES5 Much more new syntax Very , very high back compat Spec drafts Spec drafts ~ Monthly updates Currently at Rev 25 Spec ‘feature complete’ ‘Final’ spec target 7/2014
E N D
ECMAScript 6 Luke Hoban git.io/es6features
ECMAScript 6 • ES6 • More significant changes than ES5 • Much more new syntax • Very, very high back compat • Spec drafts • Spec drafts • ~ Monthly updates • Currently at Rev 25 • Spec ‘feature complete’ • ‘Final’ spec target 7/2014 • ECMA ratification target 12/2014 • Implementation progress: http://kangax.github.io/es5-compat-table/es6/
arrows // Expression bodies varodds = evens.map(v => v + 1); varnums = evens.map((v, i) => v + i); // Statement bodies nums.forEach(v => { if(v % 5 === 0) fives.push(v); }); // Lexical this var bob = { _name: "Bob", _friends: [], printFriends() { this._friends.forEach(f => console.log(this._name + " knows " + f)); } } • Function shorthand with => • Syntactically similar to C#, Java 8, CoffeeScript • Support for expression and statement bodies • Goal: Shorthand for common usage of functions as callbacks
classes classSkinnedMeshextendsTHREE.Mesh { constructor(geometry, materials) { super(geometry, materials); this.idMatrix= SkinnedMesh.defaultMatrix(); this.bones= []; this.boneMatrices= []; //... } update(camera) { //... super.update(); } staticdefaultMatrix() { return new THREE.Matrix4(); } } • Simple classes as sugar • Compiles to prototype-based OO pattern • Formalizes common JS OO pattern into syntax • Goal: Declarative classes covering common case
enhanced object literals varobj= { // __proto__ __proto__: theProtoObj, // Shorthand for ‘handler: handler’ handler, // Methods toString() { // Super calls return"d " + super.toString() } }; • Richer object literals • Covers common scenarios like: • setting prototype at construction • defining methods • accessing super from method
template strings // Basic literal string creation `In JavaScript '\n' is a line-feed.` // Multiline strings `In JavaScript this is not legal.` // Construct a DOM query varname = "Bob", time = "today"; `Hello ${name}, how are you ${time}?` // Construct an HTTP request // Prefix is used to interpret the // replacements and construction GET`http://foo.org/bar?a=${a}&b=${b}Content-Type: application/json X-Credentials: ${credentials} { "foo": ${foo}, "bar": ${bar}}`(myOnReadyStateChangeHandler); • Syntactic sugar for string construction • Similar to string interpolation in Perl, Python • Goal: Make it easier to construct strings with less risk of injection attacks
destructuring // list matching var[a, , b] = [1,2,3]; // object matching var{ op: a, lhs: { op: b }, rhs: c } = getASTNode() // Can be used in parameter position function g({name: x}) { console.log(x); } g({name: 5}) • Binding via pattern matching • Support for matching arrays, objects
default + rest + spread function f(x, y=12) { // y is 12 if not passed return x + y; } f(3) function f(x, ...y) { // y is an Array returnx * y.length; } f(3, "hello", true) function f(x, y, z) { return x + y + z; } // Pass each elem of array as argument f(...[1,2,3]) • Callee-evaluated default parameter values • Turn an array into consecutive arguments in a function call • Bind trailing parameters to an array • Goal: Write less code, replace ‘arguments’
map + set + weakmap // 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 varwm = newWeakMap(); m.set(s, { extra: 42 }); m.size === undefined • Efficient Map and Set data structures • WeakMap provides leak-free object-key’d side tables • Goal: Enable libraries to provide new experiences
proxies varhandler = { getOwnPropertyDescriptor: ..., getOwnPropertyNames: ..., defineProperty: ..., deleteProperty: ..., get: ..., set: ..., // … } varobj= {x: 1}; // Create a proxy wrapping an object var proxy = Proxy(obj, handler); // Invokes trap on handler proxy.x = 3; • Enable creation of objects with full range of behaviors available to host object • Support interception, object virtualization, logging/profiling, etc. • Continue the direction set by Object.* in ES5 • Goal: Enable libraries to provide new experiences • Semantics: Proxy semantics restricted to “proxy” objects, not general interception
symbols (function() { // module scoped symbol varkey = Symbol("key"); functionMyClass(privateData) { this[key] = privateData; } MyClass.prototype= { doStuff: function() { ... this[key] ... } }; })(); var c = newMyClass("hello") c["key"] === undefined • Allow properties to be keyed by either string (as in ES5) or Symbols • Symbols are a new primitive type • Optional ‘name’ parameter used in debugging • Goal: Enable granular access control to per-instance properties • Note: Originally two kinds ‘private’ and ‘unique’. • Private are not exposed to reflection APIs. These were postponed out of ES6 due to complexities rationalizing with proxies and other reflection mechanisms. • Unique are exposed to reflection like normal properties. There continues to be discussion about whether these are worth it given the limitied benefit over “_key”.
subclassablebuiltins // Psuedo-code of Array class Array { constructor(...args) { /* ... */ } static [Symbol.create]() { // Install special [[DefineOwnProperty]] // to magically update 'length' } } // User code of Array subclass classMyArrayextends Array { constructor(...args) { super(...args); } } // Two-phase 'new': // 1) Call @@create to allocate object // 2) Invoke constructor on new instance vararr = newMyArray(); arr[1] = 12; arr.length == 2 • Construction for Ctor now uses two-phases (both virtually dispatched): • Call Ctor[@@create] to allocate the object, installing any special behavior • Invoke constructor on new instance to initialize • The known @@create symbol is available via Symbol.create • Built-ins now expose their @@create explicitly • Goal: Enable subclassing built-ins like Array, Date and DOM. • Note: Web components can leverage DOM subclassability.
tail calls function factorial(n, acc = 1) { 'use strict'; if (n <= 1) returnacc; return factorial(n - 1, n * acc); } // Stack overflow in most implementations today, // but safe on arbitrary inputs in eS6 factorial(100000) • Calls in tail-position are guaranteed to not grow the stack unboundedly. • Makes recursive algorithms safe in the face of unbounded inputs. • Provides a better compilation target for languages that depend on tail call optimization
let + const functionf() { { let x; { // okay, block scoped name constx = "sneaky"; // error, const x = "foo"; } // error, already declared in block letx = "inner"; } } • Block-scoped binding • ‘let’ is the new ‘var’ • ‘const’ is single-assignment • Goal: Address existing confusion around scoping, align with expectation from other C-style languages • Goal: ‘const’ offers optimization opportunities • Semantics: No use before definition
iterators + for..of varfibonacci = { [Symbol.iterator]() { varpre = 0, cur = 1; return{ next() { vartemp = pre; pre = cur; cur += temp; return{ done: false, value: cur } } } } } for (var n offibonacci) { // truncate the sequence at 1000 if (n > 1000) break; print(n); } • Iterator objects enable custom iteration like CLR IEnumerable or Java Iteratable • Generalize for-in to custom iterator-based iteration with for-of • Don’t require realizing an array • Goal: Open up new kinds of iteration, including databases (LINQ) interface IteratorResult { done: boolean; value: any; } interface Iterator { next(): IteratorResult; } interface Iterable { [Symbol.iterator](): Iterator }
generators varfibonacci = { [Symbol.iterator]: function*() { varpre = 0, cur = 1; for (;;) { var temp = pre; pre = cur; cur += temp; yield cur; } } } for (var n offibonacci) { // truncate the sequence at 1000 if (n > 1000) break; print(n); } • Simplify iterator-authoring using ‘function*’ and ‘yield’ • A function declared as function* returns a Generator instance • Generators are subtypes of Iterators • Notably enabling values to flow back into the generator • So ‘yield’ is an expression form which returns a value (or throws) interface Generator extends Iterator { next(value?: any): IteratorResult; throw(exception: any); } • Goal: Open up new kinds of iteration, including databases (LINQ) • Note: Enables ‘await’-like async programming
comprehensions // Array comprehensions var results = [ for(cof customers) if(c.city == "Seattle") { name: c.name, age: c.age } ] // Generator comprehensions var results = { for(c of customers) if (c.city == "Seattle") { name: c.name, age: c.age } } • Sugar over simple iterator composition • Option to realize results as array or generator • Goal: Compact queries over in memory data
unicode // same as ES5.1 "𠮷".length == 2 // new RegExp behaviour, opt-in ‘u’ "𠮷".match(/./u)[0].length == 2 // new form "\u{20BB7}"=="𠮷"=="\uD842\uDFB7" // new String ops "𠮷".codePointAt(0) == 0x20BB7 // for-of iterates code points for(var c of "𠮷") { console.log(c); } • Non-breaking additions to support full Unicode • New RegExp mode to handle code points • Several new libraries to support processing strings as 21bit code points • Goal: Support building global apps in JavaScript • see also TC39 i18n library working group
modules // lib/math.js exportfunction sum(x, y) { return x + y; } exportvar pi = 3.141593; // app.js module math from "lib/math”; alert("2π = " + math.sum(math.pi, math.pi)); // otherApp.js import {sum, pi}from "lib/math”; alert("2π = " + sum(pi, pi)); • Language-level support for modules • Codify patterns from popular JavaScript module loaders (AMD, CommonJS) • Host-defined default loader • Implicitly asyncmodel – no code executes until requested modules are available and processed • Goal: Enable component definition and usage
modules (2) // lib/mathplusplus.js export * from"lib/math”; exportvare = 2.71828182846; export default function(x) { returnMath.exp(x); } // app.js module math from "lib/mathplusplus”; importexpfrom"lib/mathplusplus”; alert("2π = " + exp(math.pi, math.e)); • Default export • A single anonymous exported value • Imported with ‘import foo from …” • Imagine that jQuery might be a default export • Library author must decide – default export or multi-export? • ‘export *’ to auto-re-export • No ‘import *’ yet • This can be brittle with versioning
module loaders // 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 varloader = newLoader({ global: fixup(window) // replace ‘console.log’ }); loader.eval("console.log('hello world!';)") // Directly manipulate module cache System.get('jquery') System.set('jquery', Module({$: $})) • Dynamic loading • State isolation • Global namespace isolation • Compilation hooks • Nested virtualization • Goal: Support code loading natively in the JavaScript engine
The rest… • New Math, Number, String and Object APIs • Reflect API • RegExp extensions (/y, /u)
ES7? • Object.observe • async/await • Weak References • Parallel JavaScript • Decorators • Value objects (int64 and bignum)
git.io/es6features es-discuss@mozilla.org Q&A