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.mjsNative Module
Native Module
// 这是多少
1000000000000
   1019436871.42// 十进制
1_000_000_000_000
1_019_436_871.42// 十六进制
0b01001001_00101111_01001111
0x23_69_6F_31_38tc39/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 trueRegExp 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