2018.11
// lib.mjs
export const repeat = (string) => `${string} ${string}`;
// main.mjs
import {repeat} from './lib.mjs';
repeat('#io18');
// usage in HTML
<script type="module" src="/mypath_to_js_module.mjs"></script>
<script nomodule src="fallback.js"></script>
// preload 预加载一些公共库与代码
<link rel="modulepreload" href="lib.mjs" >
// mjs 后缀不是强制,但在 node 实验性新特性中 mjs 是必须的
node --experimental-modules main.mjs
Native Module
Native Module
// 这是多少
1000000000000
1019436871.42
// 十进制
1_000_000_000_000
1_019_436_871.42
// 十六进制
0b01001001_00101111_01001111
0x23_69_6F_31_38
tc39/proposal-numeric-separator
tc39/proposal-numeric-separator
Still in stage 2 https://github.com/tc39/proposal-numeric-separator
console.log(Number.MIN_SAFE_INTEGER); // 9007199254740991
console.log(Number.MAX_SAFE_INTEGER); // -9007199254740991
// 例子
BigInt(Number.MAX_SAFE_INTEGER) + 2n;
// → 9_007_199_254_740_993n ✅
1234567890123456789 * 123;
// → 151851850485185200000 ❌
1234567890123456789n * 123n;
// → 151851850485185185047n ✅
42n === BigInt(42);
typeof 123n; // 'bigint'
BigInt
BigInt
// old
const print = (readable) => {
readable.setEncoding('utf8');
let data = '';
readable.on('data', (chunk) => {
data += chunk;
});
readable.on('end', () => {
console.log(data);
})
}
const fs = require('fs');
print(fs.createReadStream('./file.txt'));
// new
async function print(readable) {
readable.setEncoding('utf8');
let data = '';
for await (const chunk of readable) {
data += chunk;
}
console.log(data);
}
const fs = require('fs');
print(fs.createReadStream('./file.txt'));
Async Iterator/Generator
Async Iterator/Generator
More at http://2ality.com/2016/10/asynchronous-iteration.html
const input = `
Hi, Fliggy. Hello
world.
`;
/Hello.world/u.test(input);
/Hello[\s\S]world/u.test(input); // 所有空格和所有非空格匹配 true
/Hello[^]world/u.test(input); // 所有非空 true
/Hello.world/su.test(input); // dotAll mode true
RegExp dotAll mode
RegExp dotAll mode
const pattern = /(\d{4})-(\d{2})-(\d{2})/u;
const result = pattern.exec('2017-07-10');
// result[0] === '2017-07-10'
// result[1] === '2017'
// result[2] === '07'
// result[3] === '10'
const pattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
const result = pattern.exec('2017-07-10');
// result.groups.year === '2017'
// result.groups.month === '07'
// result.groups.day === '10'
Named captures
Named captures
const string = 'Magic hex numbers: DEADBEEF CAFE 8BADF00D';
const regex = /\b\p{ASCII_Hex_Digit}+\b/gu;
let match;
while (match = regex.exec(string)) {
console.log(match);
}
for (const match of string.matchAll(regex)) {
console.log(match);
}
String Matchall
String Matchall
try {} catch (e) {} // 以前
try {} catch {} // 现在
Catch binding
Catch binding
const string = ' hello ';
string.trim(); // 'hello';
string.trimStart(); // 'hello ';
string.trimEnd(); // ' hello';
String trim
String trim
let isLoading = true;
fetch(myRequest).then(function(response) {
var contentType = response.headers.get("content-type");
if(contentType && contentType.includes("application/json")) {
return response.json();
}
throw new TypeError("Oops, we haven't got JSON!");
})
.then(function(json) {
/* process your JSON further */
isLoading = false;
})
.catch(function(error) {
isLoading = false;
console.log(error); });
// ?
let isLoading = true;
fetch(myRequest).then(function(response) {
var contentType = response.headers.get("content-type");
if(contentType && contentType.includes("application/json")) {
return response.json();
}
throw new TypeError("Oops, we haven't got JSON!");
})
.then(function(json) { /* process your JSON further */ })
.catch(function(error) { console.log(error); })
.finally(function() { isLoading = false; });
Promise.prototype.finally
Promise.prototype.finally
const person = {
firstName: 'Sebastian',
lastName: 'Markbåge',
country: 'USA',
state: 'CA',
};
const { firstName, lastName, ...rest } = person;
console.log(firstName); // Sebastian
console.log(lastName); // Markbåge
console.log(rest); // { country: 'USA', state: 'CA' }
// Merge two objects:
const defaultSettings = { logWarnings: false, logErrors: false };
const userSettings = { logErrors: true };
// The old way:
const settings1 = Object.assign({}, defaultSettings, userSettings);
// The new way:
const settings2 = { ...defaultSettings, ...userSettings };
// Either results in:
// { logWarnings: false, logErrors: true }
Object rest & spread
Object rest & spread
// 原来
class Counter extends HTMLElement {
clicked() {
this.x++;
window.requestAnimationFrame(this.render.bind(this));
}
constructor() {
super();
this.onclick = this.clicked.bind(this);
this.x = 0;
}
connectedCallback() { this.render(); }
render() {
this.textContent = this.x.toString();
}
}
window.customElements.define('num-counter', Counter);
class Counter extends HTMLElement {
x = 0;
clicked() {
this.x++;
window.requestAnimationFrame(this.render.bind(this));
}
constructor() {
super();
this.onclick = this.clicked.bind(this);
}
connectedCallback() { this.render(); }
render() {
this.textContent = this.x.toString();
}
}
window.customElements.define('num-counter', Counter);
class Counter extends HTMLElement {
#x = 0;
clicked() {
this.#x++;
window.requestAnimationFrame(this.render.bind(this));
}
constructor() {
super();
this.onclick = this.clicked.bind(this);
}
connectedCallback() { this.render(); }
render() {
this.textContent = this.#x.toString();
}
}
window.customElements.define('num-counter', Counter);
Class fileds
Class fileds
Stage 3 Proposal https://github.com/tc39/proposal-class-fields
2018.11