ES6

From Bauman National Library
This page was last modified on 22 January 2016, at 22:48.

ES6 or ECMAScript 6, also known as ECMAScript 2015, is the latest version of the ECMAScript standard. ES6 is a significant update to the language, and the first update to the language since ES5 was standardized in 2009. Goals for ECMAScript 2015 include providing better support for large applications, library creation, and for use of ECMAScript as a compilation target for other languages. Some of its major enhancements include modules, class declarations, lexical block scoping, iterators and generators, promises for asynchronous programming, destructuring patterns, and proper tail calls.

Arrows

Arrows are a function shorthand using the => syntax. They are syntactically similar to the related feature in C#, Java 8 and CoffeeScript. They support both statement block bodies as well as expression bodies which return the value of the expression. Unlike functions, arrows share the same lexical this as their surrounding code.

// Expression bodies
var odds = evens.map(v => v + 1);

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

Classes

Classes are a well-debated feature of ES6. Some believe that they go against the prototypal nature of JavaScript, while others think they lower the barrier to entry for beginners and people coming from other languages and that they help people writing large-scale applications.

Classes are built around the class and constructor keywords. Here’s a short example:

class Vehicle {
   constructor(name) {
      this.name = name;
      this.kind = 'vehicle';
   }
   getName() {
      return this.name;
   }   
}

// Create an instance
let myVehicle = new Vehicle('rocky');

To create an instance of a class, you must use the new keyword. To inherit from a base class, use extends. From the derived class, you can use super from any constructor or method to access its base class.

class Car extends Vehicle {
   constructor(name) {
      super(name);
      this.kind = 'car'
   }
}

let myCar = new Car('bumpy');

myCar.getName(); // 'bumpy'
myCar instanceof Car; // true
myCar instanceof Vehicle; //true

Promises

Promises are a library for asynchronous programming. Promises are a first class representation of a value that may be made available in the future. Promises are used in many existing JavaScript libraries.

function timeout(duration = 0) {
    return new Promise((resolve, reject) => {
        setTimeout(resolve, duration);
    })
}

var p = timeout(1000).then(() => {
    return timeout(2000);
}).then(() => {
    throw new Error("hmm");
}).catch(err => {
    return Promise.all([timeout(100), timeout(200)]);
})

Template Strings

Template strings are string literals allowing embedded expressions. You can use multi-line strings and string interpolation features with them.

// Basic literal string creation
`In JavaScript '\n' is a line-feed.`

// Multiline strings
`In JavaScript this is
 not legal.`

// String interpolation
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`

Destructuring

Destructuring allows binding using pattern matching, with support for matching arrays and objects. Destructuring is fail-soft, similar to standard object lookup foo["bar"], producing undefined values when not found.

var [a, b] = [1, 2]
var [a, b, ...rest] = [1, 2, 3, 4, 5]
var [foo, [[bar], baz]] = [1, [[2], 3]]
var {a, b} = {a:1, b:2}

var o = {p: 42, q: true};
var {p, q} = o;

// Destructuring assignment can be made 
// without a declaration in the assignment statement.
({a, b} = {a:1, b:2});

Let + Const

The let statement declares a block scope local variable, optionally initializing it to a value. This is unlike the var keyword, which defines a variable globally, or locally to an entire function regardless of block scope.

The const declaration creates a read-only reference to a value. It does not mean the value it holds is immutable, just that the variable identifier cannot be reassigned.

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

Iterators + For..Of

The iterable protocol allows JavaScript objects to define or customize their iteration behavior, such as what values are looped over in a for..of construct. Some built-in types are built-in iterables with a default iteration behavior, such as Array or Map, while other types (such as Object) are not.

In order to be iterable, an object must implement the @@iterator method, meaning that the object (or one of the objects up its prototype chain) must have a property with a Symbol.iterator key: a zero arguments function that returns an object, conforming to the iterator protocol.

The iterator protocol defines a standard way to produce a sequence of values (either finite or infinite). An object is an iterator when it implements a next() method with the following semantics:

Property Value
next A zero arguments function that returns an object with two properties:
  • done (boolean)
    • true if the iterator is past the end of the iterated sequence. In this case value optionally specifies the return value of the iterator.
    • false if the iterator was able to produce the next value in the sequence. This is equivalent of not specifying the done property altogether.
  • value - any JavaScript value returned by the iterator. Can be omitted when done is true.

Example:

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

Generators simplify iterator-authoring using function* and yield. A function declared as function* returns a Generator instance. Generators are subtypes of iterators which include additional next and throw. Inside the generator function body, you use the new yield keyword to pause the function from inside itself. An external control must be used to restart the generator.

function *foo(x) {
    var y = 2 * (yield (x + 1));
    var z = yield (y / 3);
    return (x + y + z);
}

var it = foo( 5 );

// note: not sending anything into `next()` here
console.log( it.next() );       // { value:6, done:false }
console.log( it.next( 12 ) );   // { value:8, done:false }
console.log( it.next( 13 ) );   // { value:42, done:true }

Modules

JavaScript does not have built-in support for modules, but the community has created impressive work-arounds. The two most important (and unfortunately incompatible) standards are CommonJS Modules and Asynchronous Module Definition (AMD). The goal for ECMAScript 6 modules was to create a format that both users of CommonJS and of AMD are happy with.

// 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";
alert("2π = " + sum(pi, pi));
// lib/mathplusplus.js
export * from "lib/math";
export var e = 2.71828182846;
export default function(x) {
    return Math.log(x);
}

Reference