//

ES6 ADVANCED FEATURES

We have learned about the new features ES6 brings us in ES6 New Features article. In this post, we will go through the advanced features of ES6 and how we can implement them.

Enhanced Object Literals

ES6 introduces new features for setting the prototype at contruction.

var foo = {
    // dunder proto
    __proto__: proto,
    // Shorthand for 'bar: bar'
    bar,
    // methods
    foobar() {
     // Super calls
     return 'foo' + super.bar();
    },
    // Computed (dynamic) property names
    [ "prop_" + (() => bar)() ]: bar
};

Template Strings

ES6 introduces template strings to improve the capabilities of JavaScript strings.

DSLs

This features will enable developers to define strings with domain-specific languages (DSLs).

Template strings will enable:

  • Multiline strings without hacking
  • String tagging for safe HTML escaping
  • Localization
  • String formatting
  • Embedded expressions
  • String interpolation
Syntax

Template Strings use back-ticks.

// basic single line string
`Hello "\n" how are you?`

// multiline strings
`Hello
 how are you?.`

// string interpolation
var name = 'Sally',
    time = 'today';

`Hello ${name}, how are you ${time}?`

// tagged templates
fn`Hello ${name}! how are you ${today}!`

Comprehensions

Array comprehensions are similar to map and filter.

Map & Filter

Best way to understand Array comprehensions is by comparing it with map and filter functions.

[for (i of [1, 2, 3]) i * i]; // [1, 4, 9]
[1, 2, 3].map(function (i) { return i * i }); // [1, 4, 9]

[for (i of [1,4,2,3,-8]) if (i < 3) i]; // [1, 2, -8]
[1,4,2,3,-8].filter(function(i) { return i < 3 }); // [1, 2, -8]

Unicode

ECMAScript 6 introduces two new flags for regular expressions:

  • y enables 'sticky' matching
  • u enables Unicode-related fetaures

Setting u on a regular expression enables the use of Unicode code point escapes (\u{..}) in the pattern.

// `a` is U+0061 LATIN SMALL LETTER A, a BMP symbol.
/\u{61}/u.test('a'); // true

// `` is U+1D306 TETRAGRAM FOR CENTRE, an astral symbol.
/\u{1D306}/u.test(''); // true

// new RegExp behaviour, opt-in ‘u’
"".match(/./u)[0].length == 2 // true

Module Loaders

ES6 provides you with module loades support:

  • Dynamic loading
  • State isolation
  • Global namespace isolation
  • Compilation hooks
  • Nested virtualization

With configurable default module loaders, new loaders can be constructed to evaluate and load code in isolated or constrained contexts.

// 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
var loader = new Loader({
  global: fixup(window) // replace ‘console.log’
});
loader.eval("console.log(\"hello world!\");");

// Directly manipulate module cache
System.get("jquery");
System.set("jquery", Module({$: $})); // WARNING: not yet finalized

Map + Set + WeakMap + WeakSet

ES6 brings new data structures: Map, WeakMap, Set, WeakSet.

Map - The Map data structure in ES6 lets you use arbitrary values as keys and is highly welcome.

let map = new Map();

map.set('foo', 100);
map.get('foo'); // 100

map.has('foo'); // true
map.delete('foo');
map.has('foo'); // false

WeakMap - A WeakMap is a map that doesn’t prevent its keys from being garbage-collected.

let wm = new WeakMap();
let foo = {};

wm.set(foo, 100);
wm.get(foo); // 100

wm.has(foo); // true
wm.delete(foo);
wm.has(foo); // false

Set - A Set works for arbitrary values, is fast and handles NaN correctly.

let set = new Set();
set.add('foo');

set.has('foo'); // true
set.delete('foo');
set.has('foo'); // false

WeakSet - A WeakSet is a set that doesn’t prevent its elements from being garbage-collected.

Garbage Collection

When using a WeakMap or WeakSet allows us to associate data with objects without having to worry about memory leaks.

Subclassable Built-ins

Creatng sub-constructors from built-ins is impossible. In ES6, built-ins like Array, Date and DOM Elements can be subclassed.

__proto__

Only works in current browsers with JavaScript engines that support __proto__.

function Foo(len) {
  var array = new Array(len);
  array.__proto__ = Foo.prototype;
  return array;
}

var foo = new Foo(5);
foo.length; // 5

Foo.prototype = Object.create(Array.prototype);

Foo.length; // 1

Binary and Octal Literals

In ES6, you can specifiy two new numeric literals for integers in binary b and octal 0.

// binary
0b101; // 5

// octal
0o10; // 8

Reflect API

Reflection API exposese the runtime-level meta-operations on objects.

Reflect API:

  • Not a functional object.
  • No construtor available, so new cannot be used with it.
  • No call or apply internal methods available.
var Foo = {a: 1};
Object.defineProperty(O, 'b', {value: 2});
Foo[Symbol('c')] = 3;

Reflect.ownKeys(Foo); // ['a', 'b', Symbol(c)]

function C(a, b){
  this.c = a + b;
}

var instance = Reflect.construct(C, [10, 12]);
console.log(instance.c); // 22

Tail Calls

A tail call happens when a function makes a function call as its final action. At that point the function will do absolutely no more work: it passes the execution to whatever function is being called and disappears.This is guaranteed to not grow the stack unboundedly. Makes recursive algorithms like Fibonaccisafe in the face of unbounded inputs.

function factorial(n) {
    function recur(n, acc) {
        if (n === 0) {
            return acc;
        } else {
            return recur(n-1, n*acc);
        }
    }
    return recur(n, 1);
}

factorial(100000);