ES6 Reference
Published: | Fri 21 December 2018 |
By: | Brian Shen |
Category: | Node |
Tags: | Node |
Contents
1. let & const
Just use them.
2. destructuring
2.1. Usage
Exchange value
let x = 1; let y = 2; [x, y] = [y, x];
Return many values
function example() { return { foo: 1, bar: 2 }; } let { foo, bar } = example();
Function definition
function f([x, y, z]) { ... } f([1, 2, 3]); function f({x, y, z}) { ... } f({z: 3, y: 2, x: 1});
JSON extraction
let jsonData = { id: 42, status: "OK", data: [867, 5309] }; let { id, status, data: number } = jsonData;
Default function parameter
jQuery.ajax = function (url, { async = true, beforeSend = function () {}, cache = true, complete = function () {}, crossDomain = false, global = true, // ... more config } = {}) { // ... do stuff };
Map iteration
for (let [key, value] of map) { console.log(key + " is " + value); }
Module import
const { SourceMapConsumer, SourceNode } = require("source-map");
3. String
3.1. Unicode
'\z' === 'z' // true
'\172' === 'z' // true
'\x7A' === 'z' // true
'\u007A' === 'z' // true // less than FFFF
'\u{7A}' === 'z' // true // greater than FFFF (4 byte)
3.2. codePointAt
Handle characters taken more than 4 bytes.
var s = "𠮷a";
s.length // 2
s.charAt(0) // ''
s.charAt(1) // ''
s.charCodeAt(0) // 55362
s.charCodeAt(1) // 57271
s.codePointAt(0) // 134071
s.codePointAt(1) // 57271
s.codePointAt(2) // 97
3.3. fromCodePoint
Only handle characters taken more than 4 bytes.
String.fromCodePoint(0x20BB7)
// "𠮷"
3.4. iteration
for...of
syntax can handler all kinds of characters.
let text = String.fromCodePoint(0x20BB7);
for (let i = 0; i < text.length; i++) {
console.log(text[i]);
}
// " "
// " "
for (let i of text) {
console.log(i);
}
// "𠮷"
3.5. normalize
Handle European Characters.
3.6. newAPIs
includes()
startsWith()
endsWith()
endsWith()
padStart()
padEnd()
3.7. String Template
let str = `There are <b>${basket.count}</b> items`
4. Regex
4.1. Unicode support u
var s = '𠮷';
/^.$/.test(s) // false
/^.$/u.test(s) // true
/\u{61}/.test('a') // false
/\u{61}/u.test('a') // true
/\u{20BB7}/u.test('𠮷') // true
/a{2}/.test('aa') // true
/a{2}/u.test('aa') // true
/𠮷{2}/.test('𠮷𠮷') // false
/𠮷{2}/u.test('𠮷𠮷') // true
4.2. Stick y
y
begin after all match while g
begin at next character.
var s = 'aaa_aa_a';
var r1 = /a+/g;
var r2 = /a+/y;
r1.exec(s) // ["aaa"]
r2.exec(s) // ["aaa"]
r1.exec(s) // ["aa"]
r2.exec(s) // null
4.3. dotAll s
We can support all characters. dot only represents normal characters.
/foo.bar/.test('foo\nbar')
// false
/foo.bar/s.test('foo\nbar') // true
5. Number
5.1. APIS
isFinite, isNaN
Number.isFinite(15); // true Number.isFinite(0.8); // true Number.isFinite(NaN); // false Number.isFinite(Infinity); // false Number.isFinite(-Infinity); // false Number.isFinite('foo'); // false Number.isFinite('15'); // false Number.isFinite(true); // false Number.isNaN(NaN) // true Number.isNaN(15) // false Number.isNaN('15') // false Number.isNaN(true) // false Number.isNaN(9/NaN) // true Number.isNaN('true' / 0) // true Number.isNaN('true' / 'true') // true
parseInt
parseFloat
isInteger
isSafeInteger ( -2^53 ~ 2^53 )
6. Function
6.1. Rest parameters
...varaiable
to get all rest parameters. Array.
function add(...values) {
let sum = 0;
for (var val of values) {
sum += val;
}
return sum;
}
add(2, 5, 3) // 10
6.2. strict mode
Under strict mode, functions won't include func.arguments
and func.caller
.
If we want to use strict mode, then the function itself cannot include - default value - deconstructing
Error:
function doSomething(a, b = a) {
'use strict';
// code
}
const doSomething = function ({a, b}) {
'use strict';
// code
};
const doSomething = (...a) => {
'use strict';
// code
};
const obj = {
doSomething({a, b}) {
'use strict';
// code
}
};
How we can avoid this:
# 1
'use strict';
function doSomething(a, b = a) {
// code
}
# 2
const doSomething = (function () {
'use strict';
return function(value = 42) {
return value;
};
}());
6.3. Array Function
Watch:
- there is no this
in function, this
is the outside this
.
- cannot use as a constructor
- cannot use arguments object
- cannot use yield
7. Array
7.1. spread operator
console.log(...[1, 2, 3])
// 1 2 3
Usage:
clone
const a1 = [1, 2]; const a2 = [...a1];
combine
const arr1 = ['a', 'b']; const arr2 = ['c']; [...arr1, ...arr2]
String length
'x\uD83D\uDE80y'.length // 4 [...'x\uD83D\uDE80y'].length // 3
generator
const go = function*(){ yield 1; yield 2; yield 3; }; [...go()] // [1, 2, 3]
APIs
Array.from
let arrayLike = { '0': 'a', '1': 'b', '2': 'c', length: 3 }; let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
Array.Of
Array constructor exists some misunderstanding.
Array.of(3, 11, 8) // [3,11,8] Array.of(3) // [3] Array.of(3).length // 1 Array() // [] Array(3) // [, , ,] Array(3, 11, 8) // [3, 11, 8]
find, findIndex
fill
entries(),keys() and values()
for (let index of ['a', 'b'].keys()) { console.log(index); } // 0 // 1 for (let elem of ['a', 'b'].values()) { console.log(elem); } // 'a' // 'b' for (let [index, elem] of ['a', 'b'].entries()) { console.log(index, elem); } // 0 "a" // 1 "b" let letter = ['a', 'b', 'c']; let entries = letter.entries(); console.log(entries.next().value); // [0, 'a'] console.log(entries.next().value); // [1, 'b'] console.log(entries.next().value); // [2, 'c']
includes
flat, flatMap
[1, 2, [3, 4]].flat() // [1, 2, 3, 4] [2, 3, 4].flatMap((x) => [x, x * 2]) // [2, 4, 3, 6, 4, 8]
8. Object
8.1. syntax
const foo = 'bar';
const baz = {foo};
baz // {foo: "bar"}
let lastWord = 'last word';
const a = {
'first word': 'hello',
[lastWord]: 'world'
};
a['first word'] // "hello"
a[lastWord] // "world"
a['last word'] // "world"
!!!! Don't use object as a key.
const keyA = {a: 1};
const keyB = {b: 2};
const myObject = {
[keyA]: 'valueA',
[keyB]: 'valueB'
};
myObject // Object {[object Object]: "valueB"}
8.2. ATTR
name
const person = { sayName() { console.log('hello!'); }, }; person.sayName.name // "sayName"
super
(Only in function of an object)Point to the prototype.
const proto = { foo: 'hello' }; const obj = { foo: 'world', find() { return super.foo; } }; Object.setPrototypeOf(obj, proto); obj.find() // "hello"
8.3. Operator
let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }
let foo = { ...['a', 'b', 'c'] };
foo
// {0: "a", 1: "b", 2: "c"}
let aClone = { ...a };
// Same as
let aClone = Object.assign({}, a);
8.4. APIs
Object.is
same as===
.Object.assign
- Shallow Copy - Array handle as objectObject.assign([1, 2, 3], [4, 5]) // [4, 5, 3]
- get value and then overwrite
Object.getOwnPropertyDescriptor
set, get special functions.
const source = { set foo(value) { console.log(value); } }; const target2 = {}; Object.defineProperties(target2, Object.getOwnPropertyDescriptors(source)); Object.getOwnPropertyDescriptor(target2, 'foo') // { get: undefined, // set: [Function: set foo], // enumerable: true, // configurable: true }
__proto__ ,Object.setPrototypeOf(),Object.getPrototypeOf()
Object.keys(),Object.values(),Object.entries()
Object.fromEntries()
adverse ofentries
, from Map to Object.
9. Symbol
9.1. Usage
Object has various attributes which are defined in string. So it is very easy to overwrite them. Symbol is unique and is the 7th type of js.
let s = Symbol();
typeof s
// "symbol"
let s1 = Symbol('foo');
let s2 = Symbol('bar');
s1 // Symbol(foo)
s2 // Symbol(bar)
s1.toString() // "Symbol(foo)"
s2.toString() // "Symbol(bar)"
let s1 = Symbol();
let s2 = Symbol();
s1 === s2 // false
let s1 = Symbol('foo');
let s2 = Symbol('foo');
s1 === s2 // false
Symbol can turn to strings only in explicit way.
9.2. Iteration
When we use Symbol as an attribute, then , it won't appear in iterations.
- for...in
- for...of
- Object.keys()
- Object.getOwnPropertyNames()
- JSON.stringify()
We can get these attributes with Object.getOwnPropertySymbols
.
9.3. APIs
Symbol.for (create or get)
let s1 = Symbol.for('foo'); let s2 = Symbol.for('foo'); s1 === s2 // true
Symbol.keyFor
let s1 = Symbol.for("foo"); Symbol.keyFor(s1) // "foo" let s2 = Symbol("foo"); Symbol.keyFor(s2) // undefined
10. Set and Map
10.1. Set
const s = new Set();
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
for (let i of s) {
console.log(i);
}
// 2 3 5 4
const set = new Set([1, 2, 3, 4, 4]);
[...set]
// [1, 2, 3, 4]
- size
- add()
- delete()
- has()
- clear()
- keys()
- values()
- entries()
- forEach()
10.2. Map
Hash Key Value. But, we can add everything as a key.
const map = new Map([
['name', '张三'],
['title', 'Author']
]);
map.size // 2
map.has('name') // true
map.get('name') // "张三"
map.has('title') // true
map.get('title') // "Author"
const items = [
['name', '张三'],
['title', 'Author']
];
const map = new Map();
items.forEach(
([key, value]) => map.set(key, value)
);
- size
- add()
- delete()
- has()
- clear()
- keys()
- values()
- entries()
- forEach()
11. Proxy
meta programming, which can change language.
var obj = new Proxy({}, {
get: function (target, key, receiver) {
console.log(`getting ${key}!`);
return Reflect.get(target, key, receiver);
},
set: function (target, key, value, receiver) {
console.log(`setting ${key}!`);
return Reflect.set(target, key, value, receiver);
}
});
obj.count = 1
// setting count!
++obj.count
// getting count!
// setting count!
// 2
11.1. Proxy Actions Supoorted
- get(target, propKey, receiver)
- set(target, propKey, value, receiver)
- has(target, propKey)
- deleteProperty(target, propKey)
- ownKeys(target)
- getOwnPropertyDescriptor(target, propKey)
- defineProperty(target, propKey, propDesc)
- preventExtensions(target)
- getPrototypeOf(target)
- isExtensible(target)
- setPrototypeOf(target, proto)
- apply(target, object, args)
- construct(target, args)
11.2. Proxy.revocable
Stop proxy.
let target = {};
let handler = {};
let {proxy, revoke} = Proxy.revocable(target, handler);
proxy.foo = 123;
proxy.foo // 123
revoke();
proxy.foo // TypeError: Revoked
11.3. This
This will point to Proxy itself.
const target = {
m: function () {
console.log(this === proxy);
}
};
const handler = {};
const proxy = new Proxy(target, handler);
target.m() // false
proxy.m() // true
12. Reflect
Why: - Move some Object internal functions to Reflect - Refine some APIs that Object provides - Make all actions become functions (name in object => has() ) - Reflect and Proxy Combination
Proxy(target, { set: function(target, name, value, receiver) { var success = Reflect.set(target,name, value, receiver); if (success) { console.log('property ' + name + ' on ' + target + ' set to ' + value); } return success; } });
Methods:
- Reflect.apply(target, thisArg, args)
- Reflect.construct(target, args)
- Reflect.get(target, name, receiver)
- Reflect.set(target, name, value, receiver)
- Reflect.defineProperty(target, name, desc)
- Reflect.deleteProperty(target, name)
- Reflect.has(target, name)
- Reflect.ownKeys(target)
- Reflect.isExtensible(target)
- Reflect.preventExtensions(target)
- Reflect.getOwnPropertyDescriptor(target, name)
- Reflect.getPrototypeOf(target)
- Reflect.setPrototypeOf(target, prototype)
13. Promises
3 States: - pending - fulfilled (resolved) - rejected
const promise = new Promise(function(resolve, reject) {
// ... some code
if (success){
resolve(value);
} else {
reject(error);
}
});
Once created, it will run. Resolve and Reject cannot terminate Promise. So, always add return.
13.1. APIs
then
getJSON("/post/1.json").then( post => getJSON(post.commentURL) ).then( comments => console.log("resolved: ", comments), err => console.log("rejected: ", err) );
catch
Alias of
.then(null, rejection)
.then can append after catch as catch itself will return a promise.
finally
promise .then(result => {···}) .catch(error => {···}) .finally(() => {···});
all
const promises = [2, 3, 5, 7, 11, 13].map(function (id) { return getJSON('/post/' + id + ".json"); }); Promise.all(promises).then(function (posts) { // ... }).catch(function(reason){ // ... });
race
Only one promise needs to be finished.
const p = Promise.race([ fetch('/resource-that-may-take-a-while'), new Promise(function (resolve, reject) { setTimeout(() => reject(new Error('request timeout')), 5000) }) ]); p .then(console.log) .catch(console.error);
resolve
Turn an object to a Promise object
const jsPromise = Promise.resolve($.ajax('/whatever.json'));
reject
const p = Promise.reject('wrong'); // same const p = new Promise((resolve, reject) => reject('wrong')) p.then(null, function (s) { console.log(s) });
14. Iterator
If a data structure has Symbol.iterator
attribute, then it is iterable.
And we can use for...of
to iterate it.
const obj = {
[Symbol.iterator] : function () {
return {
next: function () {
return {
value: 1,
done: true
};
}
};
}
};
Native iterable objects:
- Array
- Map
- Set
- String
- TypedArray
- arguments object in function
- NodeList
Sample:
let arr = ['a', 'b', 'c'];
let iter = arr[Symbol.iterator]();
iter.next() // { value: 'a', done: false }
iter.next() // { value: 'b', done: false }
iter.next() // { value: 'c', done: false }
iter.next() // { value: undefined, done: true }
When we use it? - destruct and assign
let set = new Set().add('a').add('b').add('c'); let [x,y] = set; // x='a'; y='b' let [first, ...rest] = set; // first='a'; rest=['b','c'];
expand operator
...
yield*
let generator = function* () { yield 1; yield* [2,3,4]; yield 5; }; var iterator = generator(); iterator.next() // { value: 1, done: false } iterator.next() // { value: 2, done: false } iterator.next() // { value: 3, done: false } iterator.next() // { value: 4, done: false } iterator.next() // { value: 5, done: false } iterator.next() // { value: undefined, done: true }
15. Generator
State Machine.
- A *
between function
and name.
- use yeild
.
When we call generator, it doesn't run. Instead, it return a pointer to internal content.
We should call next
to get next state.
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
hw.next()
// { value: 'hello', done: false }
hw.next()
// { value: 'world', done: false }
hw.next()
// { value: 'ending', done: true }
hw.next()
// { value: undefined, done: true }
Legal syntax:
function * foo(x, y) { ··· }
function *foo(x, y) { ··· }
function* foo(x, y) { ··· }
function*foo(x, y) { ··· }
A parameter can be added to next function. And this value will be regarded as the previous yeild value.
function* f() {
for(var i = 0; true; i++) {
var reset = yield i;
if(reset) { i = -1; }
}
}
var g = f();
g.next() // { value: 0, done: false }
g.next() // { value: 1, done: false }
g.next(true) // { value: 0, done: false }
Complex:
function* foo(x) {
var y = 2 * (yield (x + 1));
var z = yield (y / 3);
return (x + y + z);
}
var a = foo(5);
a.next() // Object{value:6, done:false}
a.next() // Object{value:NaN, done:false}
a.next() // Object{value:NaN, done:true}
var b = foo(5);
b.next() // { value:6, done:false } x = 5
b.next(12) // { value:8, done:false } y = 2*12, yield = 24/3 = 8
b.next(13) // { value:42, done:true } z = 13, so 5+ 24 + 13 = 42
function* numbers () {
yield 1
yield 2
return 3
yield 4
}
[...numbers()] // [1, 2]
Array.from(numbers()) // [1, 2]
let [x, y] = numbers();
x // 1
y // 2
for (let n of numbers()) {
console.log(n)
}
// 1
// 2
- throw
var g = function* () {
try {
yield;
} catch (e) {
console.log('Internal', e);
}
};
var i = g();
i.next();
try {
i.throw('a');
i.throw('b');
} catch (e) {
console.log('External', e);
}
// Internal a
// External b
- return
terminate iteration.
function* gen() {
yield 1;
yield 2;
yield 3;
}
var g = gen();
g.next() // { value: 1, done: false }
g.return('foo') // { value: "foo", done: true }
g.next() // { value: undefined, done: true }
yield *
: call another generator
function* bar() {
yield 'x';
yield* foo();
yield 'y';
}
- generator function as an object attribution
let obj = {
* myGeneratorMethod() {
···
}
};
let obj = {
myGeneratorMethod: function* () {
// ···
}
};
16. Class
# Old
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return '(' + this.x + ', ' + this.y + ')';
};
var p = new Point(1, 2);
# New
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
16.1. class specials
constructor
getter and setter
class MyClass { constructor() { // ... } get prop() { return 'getter'; } set prop(value) { console.log('setter: '+value); } } let inst = new MyClass(); inst.prop = 123; // setter: 123 inst.prop // 'getter'
Another form
const MyClass = class Me { getClassName() { return Me.name; } }; let inst = new MyClass(); inst.getClassName() // Me Me.name // ReferenceError: Me is not defined
16.2. Warnings
- default use strict
- class will not hoist, move definition to the top.
16.3. Static
class Foo {
static classMethod() {
return 'hello';
}
}
Foo.classMethod() // 'hello'
var foo = new Foo();
foo.classMethod()
// TypeError: foo.classMethod is not a function
class Foo {
static classMethod() {
return 'hello';
}
}
class Bar extends Foo {
}
Bar.classMethod() // 'hello'
class Foo {
}
Foo.prop = 1;
Foo.prop // 1
16.4. attrs
class IncreasingCounter {
constructor() {
this._count = 0;
}
get value() {
console.log('Getting the current value!');
return this._count;
}
increment() {
this._count++;
}
}
// same
class IncreasingCounter {
_count = 0;
get value() {
console.log('Getting the current value!');
return this._count;
}
increment() {
this._count++;
}
}
16.5. private variables and attrs
class Widget {
// public
foo (baz) {
this._bar(baz);
}
// private
_bar(baz) {
return this.snaf = baz;
}
// ...
}
And we can use symbol. But it is a little strange.
const bar = Symbol('bar');
const snaf = Symbol('snaf');
export default class myClass{
// public
foo(baz) {
this[bar](baz);
}
// private
[bar](baz) {
return this[snaf] = baz;
}
// ...
};
16.6. new.target
Constructor or copy-constructor
function Person(name) {
if (new.target !== undefined) {
this.name = name;
} else {
throw new Error('must use new ');
}
}
// or
function Person(name) {
if (new.target === Person) {
this.name = name;
} else {
throw new Error('must use new ');
}
}
var person = new Person('a'); // correct
var notAPerson = Person.call(person, 'a'); // error
In a derived class, new.target will return derived class.
16.7. extends
super must be called to initialize parent instance. And this can be used after super.
class Point {
}
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y); // 调用父类的constructor(x, y)
this.color = color;
}
toString() {
return this.color + ' ' + super.toString(); // 调用父类的toString()
}
}
if constructor is not defined, then:
class ColorPoint extends Point {
}
// same
class ColorPoint extends Point {
constructor(...args) {
super(...args);
}
}
16.8. super
when we use super as an object, that means we are using Parent.prototype
.
class A {
constructor() {
this.p = 2;
}
}
class B extends A {
get m() {
return super.p;
}
}
let b = new B();
b.m // undefined
Child class calls parent class functions,
this
represents Child class.class A { constructor() { this.x = 1; } print() { console.log(this.x); } } class B extends A { constructor() { super(); this.x = 2; } m() { super.print(); } } let b = new B(); b.m() // 2
In Child, if we assign super a value (
super.x = 3;
), then we are also using child itself.class A { constructor() { this.x = 1; } } class B extends A { constructor() { super(); this.x = 2; super.x = 3; console.log(super.x); // undefined console.log(this.x); // 3 } } let b = new B();
in static methods, super means parent.
class Parent { static myMethod(msg) { console.log('static', msg); } myMethod(msg) { console.log('instance', msg); } } class Child extends Parent { static myMethod(msg) { super.myMethod(msg); } myMethod(msg) { super.myMethod(msg); } } Child.myMethod(1); // static 1 var child = new Child(); child.myMethod(2); // instance 2
16.9. prototype and __proto__
class A {
}
class B extends A {
}
B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true
17. Decorator
Class Decorator
Python like.
@testable class MyTestableClass { // ... } function testable(target) { target.isTestable = true; } MyTestableClass.isTestable // true
Class Function Decorator
class Person { @readonly name() { return `${this.first} ${this.last}` } }
Can't apply to pure function Because function will hoist.
var readOnly = require("some-decorator"); @readOnly function foo() { } # same var readOnly; @readOnly function foo() { } readOnly = require("some-decorator");
18. Module
CommonJS
: backend
AMD
: UI
Both CommonJS and AMD are dynamic.
But ES6 import
and export
are static.
18.1. export
export var lastName = 'Jackson';
export function multiply(x, y) {
return x * y;
};
function v1() { ... }
function v2() { ... }
export {
v1 as streamV1,
v2 as streamV2,
v2 as streamLatestVersion
};
18.2. import
Read only.
import {firstName, lastName, year} from './profile.js';
import { lastName as surname } from './profile.js';
import
will be lifetd to the top of a file.
18.3. export default
export default function crc32() {
// ...
}
import crc32 from 'crc32';
export function crc32() {
// ...
};
import {crc32} from 'crc32';
import _, { each, forEach } from 'lodash';
Using defualt will make the module in a single package.
Constants in different modules:
// constants.js 模块
export const A = 1;
export const B = 3;
export const C = 4;
// test1.js 模块
import * as constants from './constants';
console.log(constants.A); // 1
console.log(constants.B); // 3
// test2.js 模块
import {A, B} from './constants';
console.log(A); // 1
console.log(B); // 3
18.4. Browser Load ES6
<script type="module" src="./foo.js"></script> // Async
<script type="module" src="./foo.js" async></script> // Sync
18.5. ES6 VS CommonJS
- CommonJS export a copy of Value while ES6 export reference.
- CommonJS load dynamically while ES6 load statically.
Comments !