All Articles

ECMAScript 6 - Harmony


JSLogo

18 Years of Specifications


ECMAScript 1 through 5

  • Precursor

    • Brendan - Mocha
    • Netscape codenames LiveScript
    • Netscape announces JavaScript (1995)
    • Netscape releases JavaScript (1996)
  • 1 ECMA establishes specification (1997)
  • 2 ISO/IEC 16262 I18N (1998)
  • 3 RegExp, String formatting, try/catch, errors (1999)
  • 4 failure, arguing, punted and renamed Harmony (1999-2009)
  • 5 ‘use strict’, JSON, get, set, reflection (2009)
  • 5.1 international standardization (2011)

ECMA

Standards


Transpiling

  • Firefox, Chrome hot on tail
  • GWT/Type/Clojure/Dart/Coffee/JSX history
  • Compiling to ES5
  • ES6 via Babel (71%) or Traceur (58%)
  • Mana began development with ES6 via Babel
  • ES6 gets standardized (June 2015)

Compiling


Constants

  • Immutable Variables
const e = 2.718281828459045;
const π = 3.141592653589793;
e < π; // → true
e = π; // → Line 4: "e" is read-only

Scoping

  • Block-Scoped Variables
let a = [ 1 ];
for (let i = 0; i < a.length; i++) {
  let x = a[i] + 1;
}
console.log(i, x, a); // → i is not defined, x is not defined, [1]
  • Block-Scoped Functions
{
  function foo () { return 'hello'; }
  foo(); // → hello
  {
    function foo () { return 'world'; }
    foo(); // → world
  }
  foo(); // → hello
}

Arrow Functions

  • Expression Bodies
let admins = collection.map( m => m.get("admin") );
console.log(m); // → m is not defined
  • Statement Bodies
  • Lexical this
this.accepted = [];
this.collection.each((m) => {
  if (m.get("state") === "accepted")
    this.accepted.push(m);
});

Extended Parameter

  • Defaults
  • Rest Parameter
{
  initialize: function(options = {}) {
    _(this.defaults).extend(options);
  },
  generateName: function(conversation, names...) {
    console.log(names); // → ["Angie", "Ariel", "Jared"]
    conversation.set("name", names.join(", "));
  }
}
  • Spread Operator
var params = [ "kana", [true], 7 ];
[ 1, 2, ...params ].length; // → 5

Template Strings

  • String Interpolation
var lastSeenAt = `Last Seen ${manawa(this.model.get("sent_at"))}`;
  • Multiline support
console.log(`Aloha
Hawaii`); // → Aloha Hawaii
  • Raw String Access
String.raw `Hi, \n World ${ 42 }` === "Hi, \\n World 42"; // → true

Extended Literals

  • Binary and Octal
0b110010100 === 404; // → true
  • Unicode String/RegExp
"\u{0CA0}_\u{0CA0}" === "ಠ_ಠ" // → true

Enhanced Regular Expression

  • Sticky Matching
  • Efficient Parsing
let regex = /foo.bar/gy;
regex.sticky; // → true
regex.lastIndex; // → 0

regex.test('foo-bar'); // → true

regex.lastIndex; // → 7
regex.test('..foo-bar'); // → false

regex.lastIndex = 2;
regex.test('..foo-bar'); // → true

regex.lastIndex; // → 9

Enhanced Object Properties

  • Property Shorthand
var options = { animate, duration };
  • Computed Property Names
  • Method Properties
var properties = {
  color: "blue",
  [ "avatar_" + getSize() ]: 42
};

var helpers = {
    foo (a, b) {
      // …
    },
    *quux (x, y) {
      //  …
    }
};

Destructuring Assignment

  • Array Matching
var list = [ "Blue", "Red", "Yellow" ];
var [ first, , second ] = list;
[ second, first ] = [ first, second ];
  • Object Matching (Deep)
var { members, meta: { total_count, updated_at } } = payload();
  • Parameter Matching
function sum ([ x, y ]) { return x + y; }
function msgText ({ name, body }) { return `${name}: ${body}`; }
  • Fail-Soft with Defaults
var [ a = 1, b = 2, c = 3, d ] = [ 4, 5 ];

Modules

  • Export
export function randomNumber {
  return Math.floor( Math.random() * 11 );
}
  • Import
import { Input, Label } from "react-bootstrap";
  • Default
export default (x) => x * x;
  • Wildcard
import * as _ from "underscore";

Classes

  • Declaration / Inheritance
  • Expressions
  • Base Class Access
  • Static Members
  • Getters / Setters
class Group extends Party {
  constructor (name, color) {
    super(name);
    this.color = color;
  }
  static defaultGroup () {
    return new Group("Engineering", "#232b38");
  }
  set name  (name) { this._name = name; }
  get name  ()     { return this._name; }
  get color ()     { return this._color; }
}
var engineering = Group.defaultGroup();
engineering.color === "#232b38"

Symbol Type

  • Unique
  • Immutable
  • Optional Descriptions (debug)
let attributes = {};
const avatar = Symbol();
attributes[avatar] = new Avatar();

typeof avatar // → "symbol"
Object.getOwnPropertySymbols(attributes); // → [ avatar ]
Symbol("avatar") === Symbol("avatar"); // → false
  • Global Symbols
let globalAvatar = Symbol.for("avatar");

globalAvatar === Symbol.for("avatar"); // → true
Symbol.keyFor(globalAvatar); // → avatar

Iterators

  • Iterable Protocol
let fibonacci = {
  [Symbol.iterator]() {
    let pre = 0, cur = 1;
    return {
       next () {
         [ pre, cur ] = [ cur, pre + cur ];
         return { done: false, value: cur };
       }
    };
  }
};
  • For _ of _
for (let n of fibonacci) {
  if (n > 1000) break;
  console.log(n);
}

Generators

  • Iterator Protocol
  • Direct
  • Matching
  • Control-Flow
function* range (start, end, step) {
    while (start < end) {
        yield start;
        start += step;
    }
}

let evens = range(0, 10, 2);
console.log(evens.next().value); // → 0

for (let n of evens) {
  console.log(n); // → 2, 4, 6, 8
}

Data Structures

  • Sets
let alphabet = new Set();
alphabet.add("A").add("B").add("A");
alphabet.size; // → 2
alphabet.has("A"); // → true
for (let key of alphabet.values()) // insertion order
  console.log(key);
  • Maps
let member = new Map();
member.set("id", 42);
member.set(state, "accepted");
member.get(state); // → "accepted"
member.size; // → 2
for (let [ key, val ] of member.entries())
  console.log(key + " = " + val);

Typed Arrays

  • Arbitrary byte-based data structures
  • Network Protocols
  • Cryptography Algorithms
  • File Format Manipulations
let buffer = new ArrayBuffer(24); // generic

let amountDue = new Float32Array(buffer, 20,  1);

let imageData = new Uint8ClampedArray([42, 1337]);
console.log(imageData[1]); // → 255

Additional Built-in Methods

  • Object Property Assignment
  • Array Element Finding
  • String Repeating and Searching
  • Number Type and Safety Checking
  • Number Comparison / Truncation / Sign Determination
Object.assign({a: 1}, {b: 2}, {c: 3}); // → { a: 1, b: 2, c: 3 }
[ 1, 3, 4, 2 ].find(x => x > 3); // → 4

"aloha".repeat(3); // alohaalohaaloha
"/networks/lua/latest".includes("networks"); // → true
"reddit".endsWith("it"); // → true
"facebook".startsWith("face"); // → true

Number.isNaN(NaN); // → true
Number.isFinite(Infinity); // → false
Number.isSafeInteger(10007199254740992); // → false
Number.EPSILON; // instead of 2.22e-16

Math.trunc(-42.7); // → -42
Math.sign(-7); // → -1

Promises

  • Async Callback
  • Chaining
let networkPromises = this.networks.each((network) => {
  return new Promise((resolve, reject) => {
    return network.fetch((response) => {
      if (response.body) {
        resolve(response.body);
      } else {
        reject(response.error);
      }
    });
  });
});

Promise.all(networkPromises).then((data) => {
  NetworkActions.setNetworks(data);
}, (error) => {
  errorHandler(error);
});

Meta Programming

  • Proxying
var artist = { name: "Michelangelo", paintings: 253 };
var interceptor = {
  set: function (receiver, property, value) {
    console.log(property, 'is changed to', value);
    receiver[property] = value;
  }
};

artist = Proxy(artist, interceptor);
artist.paintings = 254; // → paintings is changed to 254
  • Reflection
let obj = { a: 1 };
Object.defineProperty(obj, "b", { value: 2 });
obj[Symbol("c")] = 3;
Reflect.ownKeys(obj); // → [ "a", "b", Symbol(c) ]

What is next?

  • ES7

    • Object.observe
    • Async (Event Loop Concurrency)
    • Comprehensions
    • Guards (user defined invariants!)
  • ES8

    • a long ways out
    • Macros (make your own syntax)
    • Parallel arrays

XKCD

Finito