ES6

NEW
BUILTIN
APIs


'blah'.includes('la');   // true

'blah'.startsWith('bl'); // true

'blah'.endsWith('lah');  // true

'blah'.repeat(3);        // "blahblahblah"

String

(selected examples)


Number.isNaN('NaN'); // false
/* vs */ isNaN('NaN'); // true

Number.isFinite('0'); // false
/* vs */ isFinite('0'); // true

Number

"Modularization of Globals"

(selected examples)


var array = [1, 2, 3, 4, 5];

array.copyWithin(1, 3); // [1, 4, 5, 4, 5]

array.fill(42); // [42, 42, 42, 42, 42]

Array

(selected examples)


Object.is(0, -0); // false
/* vs */ 0 === -0; // true

/* Say goodbye to _.extend() */
Object.assign({}, {name: 'moe'}, {age: 15});
// {name: "moe", age: 15}

Object

(selected examples)


var options = Object.assign({}, defaults, overrides);

/* vs */

var options = Object.assign(Object.create(defaults), overrides);

Object.assign()

Pros

  • Smaller Memory Footprint
  • Better Performance
  • Dynamic Defaults

Cons

  • May cause subtle issues

Beware of methods that only work with own properties, eg:

Object.keys(),  JSON.stringify()


var bird = {status: 'awake', mood: 'happy'};

Object.observe(bird, changes => console.log(changes));

bird.color = 'red';
bird.status = 'asleep';
delete bird.mood;

/*
[
{"type":"add","object":{"status":"asleep","color":"red"},"name":"color"},
{"type":"update","object":{"status":"asleep","color":"red"},"name":"status","oldValue":"awake"},
{"type":"delete","object":{"status":"asleep","color":"red"},"name":"mood","oldValue":"happy"}
]
*/

Object.observe()

Actually, this is part of ES7, but you can find it in the latest Chrome.

=>

Noticed the weird arrow?

UNBURDEN
FUNCTION
KEYWORD

THE

The function keyword

has been used for too many things.

function Cat(name) {
  this.name = name;
}

Cat.prototype.meow = function() {
    return 'Meow';
};

Cat.prototype.do = function(task, callback) {
    console.log(this.meow() + ', I am ' + this.name +
                ', and I was born to ' + task + '!');
    return callback();
};

var nyan = new Cat('Nyan');

nyan.do('fly', function() {
  console.log('===FLY===');
});

TIME

to

UNRAVEL

the

RAVEL

function Cat(name) {
  this.name = name;
}

Cat.prototype.meow = function() {
    return 'Meow';
};

Cat.prototype.do = function(task, callback) {
    console.log(this.meow() + ', I am ' + this.name +
                ', and I was born to ' + task + '!');
    return callback();
};

var nyan = new Cat('Nyan');

nyan.do('fly', function() {
  console.log('===FLY===');
});

Constructor

Methods

Callback

function Cat(name) {
  this.name = name;
}

Cat.prototype.meow = function() {
    return 'Meow';
};

Cat.prototype.do =
function(task, callback) {
    console.log(this.meow() +
                ', I am ' +
                this.name +
                ', and I was' +
                'born to ' +
                task + '!');

    return callback();
};
class Cat {
  constructor(name) {
    this.name = name;
  }
  
  meow() {
    return 'Meow';
  }
  
  do(task, callback) {
    console.log(this.meow() +
                ', I am ' +
                this.name +
                ', and I was' +
                'born to ' +
                task + '!');

    return callback();
  }
}
nyan.do('fly', function() {
  console.log('===FLY===');
});
nyan.do('fly',
() => console.log('===FLY==='));

Super

class SkinnedMesh extends THREE.Mesh {
  constructor(geometry, materials) {
    super(geometry, materials);

    this.idMatrix = SkinnedMesh.defaultMatrix();
    this.bones = [];
    this.boneMatrices = [];
    //...
  }
  update(camera) {
    //...
    super.update();
  }
  static defaultMatrix() {
    return new THREE.Matrix4();
  }
}

Mixins / Traits

import traits from 'es6-traits';
import React from 'react/addons';

export const {on, using} = traits();

export const autobind = {
  [Symbol.toStringTag]: 'autobind',

  constructor() {
    Object.getOwnPropertyNames(this.constructor.prototype)
          .filter(x => x.startsWith('on'))
          .map(x => this[x] = this[x].bind(this));
  }
};

export const purerender = Object.assign(React.addons.PureRenderMixin, {
  [Symbol.toStringTag]: 'purerender'
});
import React from 'react';
import {on, using, autobind, purerender} from './traits';

export default class SomeComponent extends (
  on (React.Component), using (autobind, purerender)
) {
  ...
}

NEW
PRIMITIVE

Symbols

const CONSTANTS = {
  DISPATCHER: {
    CLIENT_ACTION: Symbol(),
    SERVER_ACTION: Symbol()
  }
};

Well-known Symbols

Symbol.hasInstance
Symbol.isConcatSpreadable
Symbol.isRegExp
Symbol.iterator
Symbol.toPrimitive
Symbol.toStringTag
Symbol.unscopables

ENHANCED

LITERALS

Binary and Octal Literals

0b111110111 === 503 // true
0o767 === 503 // true

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
};

Template Literals

// Interpolate variable bindings
var name = "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}}`(myHandler);

Functional
Programming
Goodies

Destructuring

var [a, , b] = [1,2,3]; // list matching

var { op: a, lhs: { op: b }, rhs: c }
    = getASTNode(); // object matching

// object matching shorthand
var {op, lhs, rhs} = getASTNode();

// Can be used in parameter position
function g({name: x}) {
  console.log(x);
}
g({name: 5})

// Fail-soft destructuring
var [a] = [];
a === undefined;

// Fail-soft destructuring with defaults
var [a = 1] = [];
a === 1;

Rest / Spread

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

Tail Calls

function factorial(n, acc = 1) {
    "use strict";
    if (n <= 1) return acc;
    return factorial(n - 1, n * acc);
}

// Stack overflow in most implementations today,
// but safe on arbitrary inputs in eS6
factorial(100000)

D&C

(target, source, ...rest) => {
  return !source ? target :
         !rest.length ? target.reduce((m, n, k) => {
           const ratio = ~~(target.length / source.length),
                 item = source[~~(k / ratio)];

           return !item ? m.concat(n) :
                  (k + 1) % ratio ? m.concat(n) :
                  m.concat(n, item);
         }, []) :
         interleave(interleave(target, source), ...rest);
}

WE HAVE

MODULES

NOW

Import / Export

import * as math from "lib/math";

import exp, {pi, e} from "lib/mathplusplus";

export * from "lib/math";
export var e = 2.71828182846;
export default function(x) {
    return Math.exp(x);
}

OTHER
GOODIES

Let / Const

function f() {
  {
    let x;
    {
      // okay, block scoped name
      const x = "sneaky";
      // error, const
      x = "foo";
    }
    // error, already declared in block
    let x = "inner";
  }
}

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);
}

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);
}

Array / Generator

Comprehensions

// Array comprehensions
var results = [
  for(c of 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 }
);

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;

ES6: Not Yo Momma's JavaScript

By G. Kay Lee

ES6: Not Yo Momma's JavaScript

  • 6,063