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' matchingu
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, sonew
cannot be used with it. - No
call
orapply
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 Fibonacci
safe 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);