EcmaScript 6 features
by
Strings (variable substitution, multi-line, tagged template strings)
Block Scoping (let, const)
Literals (octal, binary)
Rest parameters, Spread operator
Destructuring (Array, Object)
Default parameters
Lambda function / Fat Arrow (=>)
Iterators (for ...of)
Collections (Set, has(), add(), Map, set, get)
Generators (function*, yield)
Classes (class, constructor, extends, super)
Modules (export, import)
Promises (then, catch)
Proxy (meta programming)
var singleLine = `Lorem Ipsum dolore`;
console.log(singleLine);
var multiLine = `This is a text
that spans
multiple lines.`;
console.log(multiLine);
var a = "Alice", b = "Bob";
var interpolation = `${a} and ${b} are best friends`;
console.log(interpolation);
//Tagged template string
//example url: https://developer.mozilla.org
var a = 5;
var b = 10;
function tag(strings, ...values) {
console.log(strings[0]); // "Hello "
console.log(strings[1]); // " world "
console.log(values[0]); // 15
console.log(values[1]); // 50
return "Bazinga!";
}
var v = tag`Hello ${ a + b } world ${ a * b}`;
console.log(v);
Strings (variable substitution, multi-line, tagged template strings)
// define my_fav as a constant and
// give it the value 7
const my_fav = 7;
function varTest() {
var x = 31;
if (true) {
var x = 71; // same variable!
console.log(x); // 71
}
console.log(x); // 71
}
function letTest() {
let x = 31;
if (true) {
let x = 71; // different variable
console.log(x); // 71
}
console.log(x); // 31
}
function do_something() {
console.log(foo); // no hoisting
let foo = 2;
var a = 5;
var b = 10;
if (a === 5) {
let a = 4; // The scope is inside the if-block
var b = 1; // The scope is inside the function
console.log(a); // 4
console.log(b); // 1
}
console.log(a); // 5
console.log(b); // 1
// will print 7
console.log(`my favorite number is: ${my_fav}`);
//<compile-source>:45:3: my_fav is read-only
//my_fav = 20;
//console.log(`my favorite number is: ${my_fav}`);
}
varTest();
letTest();
do_something();
Block Scoping (let, const)
console.log(0b111110111 === 503); // true
console.log(0o767 === 503); // true
let foo = 0b1111; // foo will be set to 15
let bar = 0o17; // bar will be set to 15
console.log(`foo is ${foo} and bar is ${bar}`);
Literals (octal, binary)
function format(pattern, ...rest) {
return rest;
}
console.log(format('a', 'b', 'c', 'd'));
let spread = ['shoulder', 'knees'];
let lyrics = ['head', ...spread, 'and', 'toes'];
console.log(lyrics);
Rest parameters, Spread operator
//array
var foo = ["one", "two", "three"];
var [a, b, c] = foo;
console.log(`${a} ${b} ${c}`);
var d, e;
[d, e] = [1, 2];
function f() { return [1, 2]; }
var alice, bob;
[alice, bob] = f();
console.log(`Alice is ${alice} Bob is ${bob}`);
//object
var o = {p: 42, q: true};
var {p, q} = o;
console.log(p); // 42
console.log(q); // true
// Assign new variable names
var {p: foo, q: bar} = o;
console.log(foo); // 42
console.log(bar); // true
Destructuring (Array, Object)
function multiply(a, b = 1) {
return a*b;
}
function longHand(f="foo",b="bar")
{
return { f:f, b:b };
}
function shortHand(f="foo",b="bar")
{
return { f, b};
}
console.log(`result: ${multiply(5)}`);
console.log(`longHand: ${longHand().f}`);
console.log(`shortHand: ${shortHand().b}`);
Default parameters
// An empty arrow function returns undefined
let empty = () => {};
console.log(empty());
// returns "foobar"
let result = (() => "foobar")();
console.log(result);
var simple = a => a > 15 ? 15 : a;
console.log(`result: ${simple(16)}`); // 15
console.log(`result: ${simple(10)}`); // 10
let max = (a, b) => a > b ? a : b;
console.log(`Max value: ${max(15,14)}`);
let arr = [1, 2, 3];
let squares = arr.map(x => x * x);
console.log(squares);
function Person(){
this.age = 0;
setTimeout(() => {
// |this| properly refers to the person object
this.age++;
}, 1000);
}
var p = new Person();
setTimeout(() => {
console.log(`Age: ${p.age}`);
}, 1500);
Lambda function / Fat Arrow (=>)
// Unlike for (part in thing) which iterates
// through property names of an object in a
// generic way, for (part of thing) lets the
// object decide which values it gives up on
// each iteration.
let numbers = [1,2,3];
for (let number of numbers) {
console.log(number);
}
let numbersIterator = numbers[Symbol.iterator]();
console.log(`next val: ${numbersIterator.next().done}`);
console.log(`next val: ${numbersIterator.next().done}`);
console.log(`next val: ${numbersIterator.next().done}`);
console.log(`next val: ${numbersIterator.next().done}`);
//custom
function Words(str) {
this._str = str;
}
Words.prototype[Symbol.iterator] = function() {
var re = /\S+/g;
var str = this._str;
return {
next: function() {
var match = re.exec(str);
if (match) {
return {value: match[0], done: false};
}
return {value: undefined, done: true};
}
}
};
let helloWorld = new Words("Hello world foo bar!");
for (let word of helloWorld) {
console.log(word);
}
Iterators (for ...of)
An iterator is an object with a next method that returns { done, value } tuples.
An iterable is an object which has an internal method, written in the current ES6 draft specs as obj[@@iterator](), that returns an iterator.
function* idMaker(){
var index = 0;
while(index < 3)
yield index++;
}
var gen = idMaker();
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // undefined
//infinite
function* powersOf2() {
var i = 2;
yield i;
while (true) yield i *= i;
}
for (var i of powersOf2()) {
console.log(i); //2 4 16 256
if (i > 20) break;
}
Generators (function*, yield)
Generators are functions which can be exited and later re-entered. Their context (variable bindings) will be saved across re-entrances. Note: *works in latest chrome and firefox
Text
// Sets
var s = new Set();
s.add("hello").add("goodbye").add("hello");
console.log(`set ${s.size === 2}`);//true
console.log(`set ${s.has("hello") === true}`);//true
//s.keys(), s.values(), s.entries()
for (let item of s) console.log(`set ${item}`);
// Maps
var m = new Map();
m.set("hello", 42);
m.set(s, 34);
console.log(`map ${m.get(s) == 34}`);//true
console.log(`map ${m.size}`);//2
//m.keys(), m.values(), m.entries()
for (let [key, value] of m) {
console.log(`${key} = ${value}`);
}
Collections (Set, has(), add(), Map, set, get)
The Map object is a simple key/value map. Any value (both objects and primitive values) may be used as either a key or a value.
The Set object lets you store unique values of any type, whether primitive values or object references.
// Superclass
class Person {
constructor(name) {
this.name = name;
}
describe() {
return 'Person called ' + this.name;
}
}
// Subclass
class Employee extends Person {
constructor(name, title) {
super(name);
this.title = title;
}
describe() {
return super.describe() +
' (' + this.title + ')';
}
}
let p = new Person('Alice');
let e = new Employee('Bob','CEO');
console.log(p.describe());
console.log(e.describe());
Classes (class, constructor, extends, super)
//how to import
import myModule from "my-module.js";
import "my-module.js" as myModule; // equivalent
import {myMember} from "my-module.js";
import {foo, bar} from "my-module.js";
import MyModule, {foo, bar} from "my-module.js";
import {reallyReallyLongModuleMemberName as shortName} from "my-module.js";
//how to export
export { generateRandom, sum }
var utils = {
generateRandom: function() {
return Math.random();
},
sum: function(a, b) {
return a + b;
}
};
export default utils;//one per module
//example
// lib.js
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
// main.js
import { square, diag } from 'lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5
Modules (export, import)
/* 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("Houston, we have a problem");
}).catch(err => {
return Promise.all([timeout(100), timeout(200)]);
})
/*The Promise object is used for deferred and asynchronous computations.
A Promise is in one of these states:
pending: initial state, not fulfilled or rejected.
fulfilled: successful operation
rejected: failed operation.
settled: the Promise is either fulfilled or rejected, but not pending.*/
Promises (then, catch)
//syntax
//var p = new Proxy(target, handler);
var handler = {
get: function(target, name){
return name in target?
target[name] :
37;
}
};
var p = new Proxy({}, handler);//target, handler
p.a = 1;
p.b = undefined;
console.log(p.a, p.b); // 1, undefined
console.log('c' in p, p.c); // false, 37
Proxy (meta programming)
The Proxy object is used to define custom behavior for fundamental operations (e.g. property lookup, assignment, enumeration, function invocation, etc).
handler - Placeholder object which contains traps.
traps - The methods that provide property acces. This is analogous to the concept of traps in OS.
target - Object which the proxy virtualizes. It is often used as storage backend for the proxy. Invariants (semantics that remain regarding object non-extensibility or non-configurable properties are verified against the target.