ES6について
Overview
https://github.com/lukehoban/es6features#readme
String
String.x is deprecated; use String.prototype.x instead.
非推奨の構文:
var num = 15;
String.replace(num, /5/, '2');
標準の構文:
var num = 15;
String(num).replace(/5/, '2');
Template literal
Nesting templates:
const classes = `header ${ isLargeScreen() ? '' : `icon-${item.isCollapsed ? 'expander' : 'collapser'}` }`;
タグ付けされたtemplate
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!";
}
tag`Hello ${ a + b } world ${ a * b}`;
// "Bazinga!"
http://help.wtf/es6#template_literals
// Backticks enclose a template literal; ${} interpolates arbitrary expressions
let num = 99; // see block scope
console.log(`${num} bottles of beer on the wall, ${num} bottles of beer
Take one down and pass it around, ${--num} bottles of beer!`);
// Tagged form: Attach a function that processes string fragments and evaluated
// expressions
function celsius(strings, ...values) {
let rv = '';
strings.forEach((string, index) => { // See arrow functions
rv += string;
if (typeof values[index] !== 'undefined')
rv += Math.round((values[index] - 32) / 1.8);
});
return rv;
}
// Converts all the interpolated numbers to the proper unit
console.log(celsius `Today temperatures ranged from ${60} to ${65} degrees.`);
var and let
https://eslint.org/docs/rules/no-var
ECMAScript 6 allows programmers to create variables with block scope instead of function scope using the let and const keywords. Block scope is common in many other programming languages and helps programmers avoid mistakes.
if (true) {
var i = 1;
let j = 2;
}
console.log(i) // 1
console.log(j) // ReferenceError: not defined
Default function parameters
function multiply(a, b = 1) {
return a * b;
}
Iterators and for…of
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);
}
More: Duck Typing
Modules
import and export
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export
Module Loaders
Module loaders support:
- Dynamic loading
- State isolation
- Global namespace isolation
- Compilation hooks
- Nested virtualization
The default module loader can be configured, and 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
Promises
function asyncFunction() {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('Async Hello world');
}, 16);
});
}
asyncFunction().then(function (value) {
console.log(value); // => 'Async Hello world'
}).catch(function (error) {
console.error(error);
});
Generators
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
// A generator function will return an object that implements the iteration
// protocol, i.e., it has a next() method that returns
// { value: < some value>, done: <true or false> }
function* incRand(max) { // Asterisk defines this as a generator function
while (true) {
// Pause execution after the yield, resume when next(<something>) is called
// and assign <something> to x
let x = yield Math.floor(Math.random() * max + 1);
max += x;
}
}
var rng = incRand(2); // Now we have a generator object to work with
console.log(rng.next()); // { value: <between 1 and 2>, done: false }
console.log(rng.next(3)); // as above, but between 1 and 5
console.log(rng.next()); // as above, but NaN since 5 + undefined results in NaN
console.log(rng.next(20)); // Oops, looks like we broke it! NaN again.
rng.throw(new Error('Unrecoverable generator state.')); // Will be thrown from yield
shorthand of Object initializer
https://ariya.io/2013/02/es6-and-object-literal-property-value-shorthand
// Shorthand property names (ES2015)
var a = 'foo', b = 42, c = {};
var o = {a, b, c};
// Shorthand method names (ES2015)
var o = {
property(parameters) {}
};
// Computed property names (ES2015)
var prop = 'foo';
var o = {
[prop]: 'hey',
['b' + 'ar']: 'there'
};
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
Destructuring
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables. Destructuring is fail-soft, similar to standard object lookup foo[“bar”], producing undefined values when not found.
let [n1, n2, n3, n4, ...r] = [100, 'three', 34, {number: 23}, 694, 'eighteen'];
console.log(n1, n2, n3, n4); // "100 'three' 34 { number: 23 }"
console.log(r); // "[ 694, 'eighteen' ]"
Two variables values can be swapped in one destructuring expression
var a = 1;
var b = 3;
[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1
Object Destructuring
var o = {p: 42, q: true};
var {p, q} = o;
console.log(p); // 42
console.log(q); // true
Works for function parameters
var fmt = ({id = 0, name}) => `${id}: ${name}`;
console.log(fmt({ id: 1, name: 'joe'}));
symbol
https://developer.mozilla.org/en-US/docs/Glossary/Symbol
sympol
is a primitive data type. The Symbol() function returns a value of type symbol and every returned value is unique. It does not support new Symbol()
var sym1 = Symbol();
var sym2 = Symbol('foo');
var sym3 = Symbol('foo');
Symbol('foo') === Symbol('foo'); // false
var sym = new Symbol(); // TypeError
Map + Set + WeakMap + WeakSet
Reference: Why WeakMap?
Native WeakMaps hold “weak” references to key objects, which means that they do not prevent garbage collection in case there would be no other reference to the key object. This also avoids preventing garbage collection of values in the map.
/ Sets
var s = new Set();
s.add("hello").add("goodbye").add("hello");
s.size === 2;
s.has("hello") === true;
// Maps
var m = new Map();
m.set("hello", 42);
m.set(s, 34);
m.get(s) == 34;
// Weak Maps
var wm = new WeakMap();
wm.set(s, { extra: 42 });
wm.size === undefined
// Weak Sets
var ws = new WeakSet();
ws.add({ data: 42 });
// Because the added object has no other references, it will not be held in the set
New APIs in core libraries
// Number
Number.EPSILON
Number.isInteger(Infinity) // false
Number.isNaN("NaN") // false
// Math
Math.acosh(3) // 1.762747174039086
Math.hypot(3, 4) // 5
Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2) // 2
// String
"abcde".includes("cd") // true
"abc".repeat(3) // "abcabcabc"
// Array
Array.from(document.querySelectorAll('*')) // Returns a real Array
Array.of(1, 2, 3) // Similar to new Array(...), but without special one-arg behavior
[0, 0, 0].fill(7, 1) // [0,7,7]
[1, 2, 3].find(x => x == 3) // 3
[1, 2, 3].findIndex(x => x == 2) // 1
[1, 2, 3, 4, 5].copyWithin(3, 0) // [1, 2, 3, 1, 2]
["a", "b", "c"].entries() // iterator [0, "a"], [1,"b"], [2,"c"]
["a", "b", "c"].keys() // iterator 0, 1, 2
["a", "b", "c"].values() // iterator "a", "b", "c"
// Object
Object.assign(Point, { origin: new Point(0,0) })
Proxies
The Proxy object is used to define custom behavior for fundamental operations (e.g. property lookup, assignment, enumeration, function invocation, etc).
See more examples at MDN Proxy doc
No-op forwarding proxy
var target = {};
var p = new Proxy(target, {});
p.a = 37; // operation forwarded to the target
console.log(target.a); // 37. The operation has been properly forwarded
Validation
let validator = {
set: function(obj, prop, value) {
if (prop === 'age') {
if (!Number.isInteger(value)) {
throw new TypeError('The age is not an integer');
}
if (value > 200) {
throw new RangeError('The age seems invalid');
}
}
// The default behavior to store the value
obj[prop] = value;
// Indicate success
return true;
}
};
let person = new Proxy({}, validator);
person.age = 100;
console.log(person.age); // 100
person.age = 'young'; // Throws an exception
person.age = 300; // Throws an exception
Binary and Octal Literals
0b111110111 === 503 // true
0o767 === 503 // true
その他
Reflect API
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect
Tail calls
function factorial(n, acc = 1) {
'use strict';
if (n <= 1) return acc;
return factorial(n - 1, n * acc);
}
// Stack overflow in most implementations today,
// but safe on arbitrary inputs in ES6
factorial(100000)
Unicode
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/unicode