參考文獻: https://tuobaye.com/2018/11/27/%E7%BB%86%E8%A7%A3JavaScript-ES7-ES8-ES9-%E6%96%B0%E7%89%B9%E6%80%A7/
http://www.imooc.com/article/291875
https://hijiangtao.github.io/2019/07/05/Diff-ECMAScript-2019/
ES7
1. Array.prototype.includes()方法
['a', 'b', 'c', 'd'].includes('b') // true ['a', 'b', 'c', 'd'].includes('b', 1) // true ['a', 'b', 'c', 'd'].includes('b', 2) // false
var ary1 = [NaN]; console.log(ary1.indexOf(NaN))//-1 console.log(ary1.includes(NaN))//true
2. 求冪運算符(**)
用**
來替代Math.pow。
4 ** 3
等價於
Math.pow(4,3)
let n = 4;
n **= 3;
ES8
1. Async Functions
Async Functions也就是我們常說的Async/Await。Async/Await是一種用於處理JS異步操作的語法糖,可以幫助我們擺脫回調地獄,編寫更加優雅的代碼。
通俗的理解,async關鍵字的作用是告訴編譯器對於標定的函數要區別對待。當編譯器遇到標定的函數中的await關鍵字時,要暫時停止運行,帶到await標定的函數處理完畢后,再進行相應操作。如果該函數fulfilled了,則返回值是resolve value,否則得到的就是reject value。
拿普通的promise寫法來對比:
async function asyncFunc() { const result = await otherAsyncFunc(); console.log(result); } // Equivalent to: function asyncFunc() { return otherAsyncFunc() .then(result => { console.log(result); }); }
並行處理多個函數:
async function asyncFunc() { const [result1, result2] = await Promise.all([ otherAsyncFunc1(), otherAsyncFunc2(), ]); console.log(result1, result2); } // Equivalent to: function asyncFunc() { return Promise.all([ otherAsyncFunc1(), otherAsyncFunc2(), ]) .then([result1, result2] => { console.log(result1, result2); }); }
處理錯誤:
async function asyncFunc() { try { await otherAsyncFunc(); } catch (err) { console.error(err); } } // Equivalent to: function asyncFunc() { return otherAsyncFunc() .catch(err => { console.error(err); }); }
2. SharedArrayBuffer和Atomics
SharedArrayBuffer允許在多個 workers 和主線程之間共享 SharedArrayBuffer 對象的字節。這種共享有兩個好處:
- 可以更快地在 workers 之間共享數據。
- workers 之間的協調變得更簡單和更快(與 postMessage() 相比)
API:
構造函數: new SharedArrayBuffer(length)
靜態屬性: SharedArrayBuffer[Symbol.species]
實例屬性: SharedArrayBuffer.prototype.byteLength()
SharedArrayBuffer.prototype.slice(start, end)
Atomics 方法可以用來與其他 workers 進行同步。以下兩個操作可以讓你讀取和寫入數據,並且不會被編譯器重新排列:
- Atomics.load(ta : TypedArray, index)
- Atomics.store(ta : TypedArray, index, value : T)
這個想法是使用常規操作讀取和寫入大多數數據,而 Atomics 操作(load ,store 和其他操作)可確保讀取和寫入安全。通常,要使用自定義同步機制(例如)可以基於Atomics實現。
API:
Atomic 函數的主要操作數必須是 Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array 或 Uint32Array 的一個實例。它必須包裹一個 SharedArrayBuffer.
- Atomics.load(ta : TypedArray, index) : T
讀取和返回 ta[index] 上的元素,返回數組指定位置上的值。 - Atomics.store(ta : TypedArray, index, value : T) : T
在 ta[index] 上寫入 value,並且返回 value。 - Atomics.exchange(ta : TypedArray, index, value : T) : T
將 ta[index] 上的元素設置為 value ,並且返回索引 index 原先的值。 - Atomics.compareExchange(ta : TypedArray, index, expectedValue, replacementValue) : T
如果 ta[index] 上的當前元素為 expectedValue , 那么使用 replacementValue 替換。並且返回索引 index 原先(或者未改變)的值。
- Atomics.add(ta : TypedArray, index, value) : T
執行 ta[index] += value 並返回 ta[index] 的原始值。 - Atomics.sub(ta : TypedArray, index, value) : T
執行 ta[index] -= value 並返回 ta[index] 的原始值。 - Atomics.and(ta : TypedArray, index, value) : T
執行 ta[index] &= value 並返回 ta[index] 的原始值。 - Atomics.or(ta : TypedArray, index, value) : T
執行 ta[index] |= value 並返回 ta[index] 的原始值。 - Atomics.xor(ta : TypedArray, index, value) : T
執行 ta[index] ^= value 並返回 ta[index] 的原始值。
- Atomics.wait(ta: Int32Array, index, value, timeout=Number.POSITIVE_INFINITY) : (‘not-equal’ | ‘ok’ | ‘timed-out’)
如果 ta[index] 的當前值不是 value ,則返回 ‘not-equal’。否則(等於value時)繼續等待,直到我們通過 Atomics.wake() 喚醒或直到等待超時。 在前一種情況下,返回 ‘ok’。在后一種情況下,返回’timed-out’。timeout 以毫秒為單位。記住此函數執行的操作:“如果 ta[index] 為 value,那么繼續等待” 。 - Atomics.wake(ta : Int32Array, index, count)
喚醒等待在 ta[index] 上的 count workers。
3. Object.values and Object.entries
const obj = { 10: 'xxx', 1: 'yyy', 3: 'zzz' }; Object.values(obj); // ['yyy', 'zzz', 'xxx'] Object.values('es8'); // ['e', 's', '8']
const obj = ['e', 's', '8']; Object.entries(obj); // [['0', 'e'], ['1', 's'], ['2', '8']] const obj = { 10: 'xxx', 1: 'yyy', 3: 'zzz' }; Object.entries(obj); // [['1', 'yyy'], ['3', 'zzz'], ['10': 'xxx']] Object.entries('es8'); // [['0', 'e'], ['1', 's'], ['2', '8']]
4. String padding
為 String 對象增加了 2 個函數:padStart 和 padEnd。填補字符串的首部和尾部,為了使得到的結果字符串的長度能達到給定的長度(targetLength)。你可以通過特定的字符,或者字符串,或者默認的空格填充它。
str.padStart(targetLength [, padString])
str.padEnd(targetLength [, padString])
'es8'.padStart(2); // 'es8' 'es8'.padStart(5); // ' es8' 'es8'.padStart(6, 'woof'); // 'wooes8' 'es8'.padStart(14, 'wow'); // 'wowwowwowwoes8' 'es8'.padStart(7, '0'); // '0000es8' 'es8'.padEnd(2); // 'es8' 'es8'.padEnd(5); // 'es8 ' 'es8'.padEnd(6, 'woof'); // 'es8woo' 'es8'.padEnd(14, 'wow'); // 'es8wowwowwowwo' 'es8'.padEnd(7, '6'); // 'es86666'
5. Object.getOwnPropertyDescriptors
const obj = { get es7() { return 777; }, get es8() { return 888; } }; Object.getOwnPropertyDescriptor(obj); // { // es7: { // configurable: true, // enumerable: true, // get: function es7(){}, //the getter function // set: undefined // }, // es8: { // configurable: true, // enumerable: true, // get: function es8(){}, //the getter function // set: undefined // } // }
6. 結尾逗號
// 參數定義時 function foo( param1, param2, ) {} // 函數調用時 foo( 'abc', 'def', ); // 對象中 let obj = { first: 'Jane', last: 'Doe', }; // 數組中 let arr = [ 'red', 'green', 'blue', ];
ES9新特性
1.異步迭代器:異步迭代器對象的next()方法返回了一個Promise,解析后的值跟普通的迭代器類似。
async function example() { // 普通迭代器: const iterator = createNumberIterator(); iterator.next(); // Object {value: 1, done: false} iterator.next(); // Object {value: 2, done: false} iterator.next(); // Object {value: 3, done: false} iterator.next(); // Object {value: undefined, done: true} // 異步迭代器: const asyncIterator = createAsyncNumberIterator(); const p = asyncIterator.next(); // Promise await p;// Object {value: 1, done: false} await asyncIterator.next(); // Object {value: 2, done: false} await asyncIterator.next(); // Object {value: 3, done: false} await asyncIterator.next(); // Object {value: undefined, done: true} }
2. Rest/Spread 屬性
rest參數和展開運算符,這項特性在ES6中已經引入,但是ES6中僅限於數組。在ES9中,為對象提供了像數組一樣的rest參數和擴展運算符。
const obj = { a: 1, b: 2, c: 3 } const { a, ...param } = obj; console.log(a) //1 console.log(param) //{b: 2, c: 3} function foo({a, ...param}) { console.log(a); //1 console.log(param) //{b: 2, c: 3} }
3. Promise.prototype.finally()
finally的回調總會被執行。
promise .then(result => {···}) .catch(error => {···}) .finally(() => {···});
4. 命名捕獲組
ES9中可以通過名稱來識別捕獲組:
(?<year>[0-9]{4})
before:
const RE_DATE = /([0-9]{4})-([0-9]{2})-([0-9]{2})/; const matchObj = RE_DATE.exec('1999-12-31'); const year = matchObj[1]; // 1999 const month = matchObj[2]; // 12 const day = matchObj[3]; // 31
after:
const RE_DATE = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<date>[0-9]{2})/; const matchObj = RE_DATE.exec('1999-12-31'); const year = matchObj.groups.year; // 1999 const month = matchObj.groups.month; // 12 const day = matchObj.groups.date; // 31 // 使用解構語法更為簡便 const {groups: {day, year}} = RE_DATE.exec('1999-12-31'); console.log(year); // 1999 console.log(day); // 31
ES10新特性
1. 選擇性的catch綁定
在使用try catch錯誤異常處理時,可以選擇性的給catch傳入參數(可以不給catch傳參)
正常使用try catch:
try { // do something } catch (err) { // console.log('err', err); }
在es10中使用時,可以:
try { // do something } catch { // do something
}
2. JSON.superset
背景: JSON內容可以正常包含 行分隔符(\u2028)和 段落分隔符(\u2029)而ECMAScript卻不行。
在ES10中,可以直接使用
eval('\u2029');
而不會在提示錯誤。
3. Symbol.prototype.description
為Symbol類型增加Symbol.prototype.description的一個訪問器屬性,用來獲取Symbol類型數據的描述信息。
console.log(Symbol('test').description); // 'test' console.log(Symbol.for('test').description); // 'test' console.log(Symbol.iterator.description); // 'Symbol.iterator'
4. Function.prototype.toString
在ES10之后,函數調用toString()方法,將准確返回原有信息,包括空格和注釋等。
let funcToString = function () { //do something console.log('test'); } /** "function () { //do something console.log('test'); }" */
5. Object.fromEntries()
Object.fromEntries()是Object.entries()的反轉。
const obj = { foo: 'bar', baz: 42} let res1 = Object.entries(obj); console.log(res1); // [['foo', 'bar'], ['baz', 42]] let obj1= Object.fromEntries(res1); console.log(obj1); // {foo: 'bar', baz: 42}
map轉換為object
let map = new Map([['name','alex'], ['age', 18]]); const obj2 = Object.fromEntries(map); console.log(obj2); // object {name: 'alex', age: 18}
6. 更友好的JSON.stringify
正常字符的表示不變:
JSON.stringify('𝌆') // → '"𝌆"' JSON.stringify('\uD834\uDF06') // → '"𝌆"'
而無法用 UTF-8 編碼表示的字符會被序列化為轉移序列:
JSON.stringify('\uDF06\uD834') // → '"\\udf06\\ud834"' JSON.stringify('\uDEAD') // → '"\\udead"'
7. String.prototype.{trimStart, trimEnd}
trimStart()從字符串開頭刪除空格,返回一個新的字符串,不會修改原字符串。
let str = ' hello, miss cecelia!'; console.log(str.trimStart()); // 'hello, miss cecelia!'
trimEnd()從字符串右端開始移除空白字符,返回一個新的字符串,不會修改原字符串。
let str = ' hello, miss cecelia! '; console.log(str.trimEnd()); // ' hello, miss cecelia!'
8. Array.prototype.{flat, flatMap}
Array.prototype.flat()可顯式地傳入參數,表示打平的層級。不傳參數,表示只打平第一級。
let arr = [1,2,3,[1,2,[3,[4]]]]; console.log(arr.flat()); // [1,2,3,1,2,[3,[4]]] console.log(arr.flat(2)); // [1,2,3,1,2,3,[4]]
flatMap()方法:可以看作flat和map組合在一起的結果:
['My dog', 'is awesome'].map(words => words.split(' ')) // [ [ 'My', 'dog' ], [ 'is', 'awesome' ] ] ['My dog', 'is awesome'].flatMap(words => words.split(' ')) //[ 'My', 'dog', 'is', 'awesome' ]