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:
yenables 'sticky' matchinguenables 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
construtoravailable, sonewcannot be used with it. - No
callorapplyinternal 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);