20多個小事例帶你重溫 ES10 新特性

做者:Carlos Caballero
來源: Dev
譯者:前端小智

阿里雲最近在作活動,低至2折,有興趣能夠看看:
https://promotion.aliyun.com/...

ES10 雖然沒有像 ES6 那麼多新特性,但 ES10 仍然有一些有用的特性。文本經過簡單示例來介紹了 ES10 新出來的特性。經過這種方式,我們就能夠快速理解,而不須要看太多的官方解釋。html

ES10 新特性主要以下:前端

  • 數組方法:flatflatMap
  • Object.fromEntries
  • 字符串方法:trimStarttrimEnd
  • Symbol 的 description 屬性
  • try { } catch {} // catch 的參數能夠省略了
  • JSON ⊂ ECMAScript (讓 ECMAScript 兼容全部 JSON 支持的文本)
  • 格式良好的 JSON.stringify()
  • 穩定的 Array.prototype.sort()
  • 修正後的 Function.toString
  • BigInt 是第七種 原始類型
  • 動態導入
  • 標準化 globalThis 對象

1. Array.flat() && Array.flatMap

Array.flat() 方法會按照一個可指定的深度遞歸遍歷數組,並將全部元素與遍歷到的子數組中的元素合併爲一個新數組返回。git

Array.flatMap() 方法首先使用映射函數映射每一個元素,而後將結果壓縮成一個新數組。它與 map 和 深度值1的 flat 幾乎相同,但 flatMap 一般在合併成一種方法的效率稍微高一些。github

事例一:web

Array.flat()正則表達式

let multi = [1,2,3,[4,5,6,[7,8,9,[10,11,12]]]];
multi.flat();               // [1,2,3,4,5,6,Array(4)]
multi.flat().flat();        // [1,2,3,4,5,6,7,8,9,Array(3)]
multi.flat().flat().flat(); // [1,2,3,4,5,6,7,8,9,10,11,12]
multi.flat(Infinity);       // [1,2,3,4,5,6,7,8,9,10,11,12]

Array.flatMap()算法

let array = [1, 2, 3, 4, 5];

array.map(x => [x, x * 2]);

array 如今的結果:數據庫

[Array(2), Array(2), Array(2)]
0: (2)[1, 2]
1: (2)[2, 4]
2: (2)[3, 6]

使用 flatMap 方式:json

array.flatMap(v => [v, v * 2]);
[1, 2, 2, 4, 3, 6, 4, 8, 5, 10]

綜合示例:segmentfault

clipboard.png

2.Object.fromEntries()

Object.fromEntries() 方法把鍵值對列表轉換爲一個對象。

事例一:

let obj = { apple : 10, orange : 20, banana : 30 };
let entries = Object.entries(obj);
entries;
(3) [Array(2), Array(2), Array(2)]
 0: (2) ["apple", 10]
 1: (2) ["orange", 20]
 2: (2) ["banana", 30]
let fromEntries = Object.fromEntries(entries);
{ apple: 10, orange: 20, banana: 30 }

事例二:

clipboard.png

3.String.protype.matchAll

早期的一個問題是,如何編寫正則表達式「match all」

最佳的答案將建議 String.match 與正則表達式和 /g 一塊兒使用或者帶有 /gRegExp.exec 或者帶有 /gRegExp.test

我們先看看舊規範是如何工做的。

帶字符串參數的 String.match 僅返回第一個匹配:

let string = 'Hello';
let matches = string.match('l');
console.log(matches[0]); // "l"

結果是單個 "l"(注意:匹配存儲在 matches[0] 中而不是 matches

string.matchregex 參數一塊兒使用也是如此:

使用正則表達式 /l/ 找到字符 串「hello」 中的 「l」 字符:

let string = "Hello";
let matches = string.match(/l/);
console.log(matches[0]); // "l"

添加 /g 混合

let string = "Hello";
let ret = string.match(/l/g); // (2) [「l」, 「l」];

那麼爲何要使用全新的 matchAll 方法呢? 在解疑這個問題以前,先來看看 捕獲組

正則表達式捕獲組

regex 中捕獲組只是從 () 括號中提取一個模式,可使用 /regex/.exec(string)string.match 捕捉組。

常規捕獲組是經過將模式包裝在 (pattern) 中建立的,可是要在結果對象上建立 groups 屬性,它是: (?<name>pattern)

要建立一個新的組名,只需在括號內附加 ?<name>,結果中,分組 (pattern) 匹配將成爲 group.name,並附加到 match 對象,如下是一個實例:

字符串標本匹配:

clipboard.png

這裏建立了 match.groups.colormatch.groups.bird

const string = 'black*raven lime*parrot white*seagull';
const regex = /(?<color>.*?)\*(?<bird>[a-z0-9]+)/g;
while (match = regex.exec(string))
{
    let value = match[0];
    let index = match.index;
    let input = match.input;
    console.log(`${value} at ${index} with '${input}'`);
console.log(match.groups.color);
    console.log(match.groups.bird);
}

須要屢次調用 regex.exec 方法來遍歷整個搜索結果集。 在每次迭代期間調用.exec 時,將顯示下一個結果(它不會當即返回全部匹配項),所以使用 while 循環。

輸出以下:

black*raven at 0 with 'black*raven lime*parrot white*seagull'
black
raven
lime*parrot at 11 with 'black*raven lime*parrot white*seagull'
lime
parrot
white*seagull at 23 with 'black*raven lime*parrot white*seagull'
white
seagull

但奇怪的是:

若是你從這個正則表達式中刪除 /g,你將永遠在第一個結果上建立一個無限循環。這在過去是一個巨大的痛苦。想象一下,從某個數據庫接收正則表達式時,你不肯定它的末尾是否有 /g,你得先檢查一下。

使用 .matchAll() 的好理由

  1. 在與捕獲組一塊兒使用時,它能夠更加優雅,捕獲組只是使用 () 提取模式的正則表達式的一部分。
  2. 返回一個迭代器而不是一個數組,迭代器自己是有用的。
  3. 迭代器可使用擴展運算符 (…) 轉換爲數組。
  4. 它避免了帶有 /g 標誌的正則表達式,當從數據庫或外部源檢索未知正則表達式並與陳舊的RegEx 對象一塊兒使用時,它很是有用。
  5. 使用 RegEx 對象建立的正則表達式不能使用點 (.) 操做符連接。
  6. 高級: RegEx 對象更改跟蹤最後匹配位置的內部 .lastindex 屬性,這在複雜的狀況下會形成嚴重破壞。

.matchAll() 是如何工做的?

我們嘗試匹配單詞 hello 中字母 el 的全部實例, 由於返回了迭代器,因此可使用 for…of 循環遍歷它:

// Match all occurrences of the letters: "e" or "l" 
let iterator = "hello".matchAll(/[el]/);
for (const match of iterator)
    console.log(match);

這一次你能夠跳過 /g.matchall 方法不須要它,結果以下:

[ 'e', index: 1, input: 'hello' ] // Iteration 1
[ 'l', index: 2, input: 'hello' ] // Iteration 2
[ 'l', index: 3, input: 'hello' ] // Iteration 3

使用 .matchAll() 捕獲組示例:

const string = 'black*raven lime*parrot white*seagull';
const regex = /(?<color>.*?)\*(?<bird>[a-z0-9]+)/;
for (const match of string.matchAll(regex)) {
    let value = match[0];
    let index = match.index;
    let input = match.input;
    console.log(`${value} at ${index} with '${input}'`);
console.log(match.groups.color);
    console.log(match.groups.bird);
}

請注意已經沒有 /g 標誌,由於 .matchAll() 已經包含了它,打印以下:

black*raven at 0 with 'black*raven lime*parrot white*seagull'
black
raven
lime*parrot at 11 with 'black*raven lime*parrot white*seagull'
lime
parrot
white*seagull at 23 with 'black*raven lime*parrot white*seagull'
white
seagull

也許在美學上它與原始正則表達式很是類似,執行while循環實現。可是如前所述,因爲上面提到的許多緣由,這是更好的方法,移除 /g 不會致使無限循環。

綜合事例:

clipboard.png

4.String.trimStart() 與 String.trimEnd()

trimStart() :刪除字符串的開頭空格。

trimEnd() :刪除字符串末尾的空格。

事例一:

let greeting = "     Space around     ";
greeting.trimEnd();   // "     Space around";
greeting.trimStart(); // "Space around     ";

事例二:

clipboard.png

5.Symbol.Description

description 是一個只讀屬性,它會返回 Symbol 對象的可選描述的字符串。

事例一:

let mySymbol = 'My Symbol';
let symObj = Symbol(mySymbol);
symObj; // Symbol(My Symbol)
symObj.description; // "My Symbol"

事例二:

clipboard.png

6.catch 的參數能夠省略

在過去,try/catch 語句中的 catch 語句須要一個變量。 try/catch 語句幫助捕獲終端級別的錯誤:

try {
    // Call a non-existing function undefined_Function
    undefined_Function("I'm trying");
}
catch(error) {
    // Display the error if statements inside try above fail
    console.log( error ); // undefined_Function is undefined
}

在某些狀況下,所需的錯誤變量是未使用的:

try {
    JSON.parse(text); // <--- this will fail with "text not defined"
    return true; <--- exit without error even if there is one
}
catch (redundant_sometmes) <--- this makes error variable redundant
{
    return false;
}

在 ES10 中,捕獲錯誤的變量是可選的,如今能夠跳過錯誤變量:

事例一:

try {
    JSON.parse(text);
    return true;
}
catch
{
    return false;
}

事例二:

clipboard.png

7. JSON ⊂ ECMAScript

什麼是 JSON 超集?還記得 這個符號的能夠這樣解釋該提案 JSON ⊂ ECMAScript,簡而言之就是讓 ECMAScript 兼容全部 JSON 支持的文本。ECMAScript 曾在標準 JSON.parse 部分闡明 JSON 確爲其一個子集,但因爲 JSON 內容能夠正常包含 U+2028 行分隔符與 U+2029 段落分隔符而 ECMAScript 卻不行。

該草案旨在解決這一問題。在這以前,若是你使用 JSON.parse() 執行帶如上特殊字符的字符串時,只會收到 SyntaxError 的錯誤提示。該草案一樣是向後兼容的,其對用戶惟一的影響是保持原樣,即在暫不支持特殊字符解析的運行環境中保持 SyntaxError 的報錯。

clipboard.png

8.格式良好的 JSON.stringify()

此更新修復了字符 U+D800U+DFFF 的處理,有時能夠進入 JSON 字符串。 這多是一個問題,由於 JSON.stringify 可能會將這些數字格式化爲沒有等效 UTF-8 字符的值, 但 JSON 格式須要 UTF-8 編碼。

解析方法使用格式良好的JSON字符串,如:

'{ 「prop1」 : 1, "prop2" : 2 }'; // A well-formed JSON format string

注意,要建立正確 JSON 格式的字符串,絕對須要在屬性名周圍加上雙引號。缺乏或任何其餘類型的引號都不會生成格式良好的JSON。

'{ 「prop1」 : 1, "meth" : () => {}}'; // Not JSON format string

JSON 字符串格式與 Object Literal 不一樣,後者看起來幾乎同樣,但可使用任何類型的引號括住屬性名,也能夠包含方法(JSON格式不容許使用方法):

let object_literal = { property: 1, meth: () => {} };

無論怎樣,一切彷佛都很好。第一個示例看起來是兼容的。但它們也是簡單的例子,大多數狀況下都能順利地工做!

U+2028 和 U+2029 字符

問題是, ES10 以前的 EcmaScript 實際上並不徹底支持 JSON 格式。前 ES10 時代不接受未轉義行分隔符 U+2028 和段落分隔符 U+2029 字符:

clipboard.png

對於 U+D800 - U+DFFF 之間的全部字符也是如此

若是這些字符潛入 JSON 格式的字符串(假設來自數據庫記錄),你可能會花費數小時試圖弄清楚爲何程序的其他部分會產生解析錯誤。

所以,若是你傳遞 eval 這樣的字符串 「console.log(' hello ')」,它將執行 JS語句 (經過嘗試將字符串轉換爲實際代碼),也相似於 JSON.parse 將處理你的 JSON 字符串的方式。

ES10建議的解決方案是將未配對的代理代碼點表示爲JSON轉義序列,而不是將它們做爲單個UTF-16代碼單元返回。

clipboard.png

9.穩定的 Array.prototype.sort()

V8 以前的實現對包含10個以上項的數組使用了一種不穩定的快速排序算法。

一個穩定的排序算法是當兩個鍵值相等的對象在排序後的輸出中出現的順序與在未排序的輸入中出現的順序相同時。

但狀況再也不是這樣了,ES10 提供了一個穩定的數組排序:

var fruit = [
    { name: "Apple",      count: 13, },
    { name: "Pear",       count: 12, },
    { name: "Banana",     count: 12, },
    { name: "Strawberry", count: 11, },
    { name: "Cherry",     count: 11, },
    { name: "Blackberry", count: 10, },
    { name: "Pineapple",  count: 10, }
];
// 建立排序函數:
let my_sort = (a, b) => a.count - b.count;
// 執行穩定的ES10排序:
let sorted = fruit.sort(my_sort);
console.log(sorted);

控制檯輸出(項目以相反的順序出現):

clipboard.png

事例二:

clipboard.png

10.新的 Function.toString()

函數是對象,而且每一個對象都有一個 .toString() 方法,由於它最初存在於Object.prototype.toString() 上。 全部對象(包括函數)都是經過基於原型的類繼承從它繼承的。

這意味着咱們之前已經有 funcion.toString() 方法了。

可是 ES10 進一步嘗試標準化全部對象和內置函數的字符串表示。 如下是各類新案例:

典型的例子:

function () { console.log('Hello there.'); }.toString();

輸出:

⇨ function () { console.log('Hello there.'); }

直接在方法名 .toString()

Number.parseInt.toString();
⇨ function parseInt() { [native code] }

綁定上下文:

function () { }.bind(0).toString();
⇨ function () { [native code] }

內置可調用函數對象:

Symbol.toString();
⇨ function Symbol() { [native code] }

動態生成的函數:

function* () { }.toString();
⇨ function* () { }

prototype.toString

Function.prototype.toString.call({});
⇨ Function.prototype.toString requires that 'this' be a Function"

clipboard.png

11.BigInt -任意精度整數

BigInt 是第七種 原始類型。

BigInt 是一個任意精度的整數。這意味着變量如今能夠 表示²⁵³ 數字,而不只僅是9007199254740992

const b = 1n;  // 追加 n 以建立 BigInt

在過去,不支持大於 9007199254740992 的整數值。若是超過,該值將鎖定爲 MAX_SAFE_INTEGER + 1:

const limit = Number.MAX_SAFE_INTEGER;
⇨ 9007199254740991
limit + 1;
⇨ 9007199254740992
limit + 2;
⇨ 9007199254740992 <--- MAX_SAFE_INTEGER + 1 exceeded
const larger = 9007199254740991n;
⇨ 9007199254740991n
const integer = BigInt(9007199254740991); // initialize with number
⇨ 9007199254740991n
const same = BigInt("9007199254740991"); // initialize with "string"
⇨ 9007199254740991n

clipboard.png

12.動態導入

動態導入返回請求模塊的模塊名稱空間對象的promise 。所以,能夠配合使用async/await

事例一:

element.addEventListener('click', async() => {
  const module = await import(`./api-scripts/button-click.js`);
  module.clickEvent();
})

事例二:

clipboard.png

13.標準化 globalThis 對象

這在ES10以前, globalThis 尚未標準化,在平時的項目能夠經過如下方式來兼容不一樣的平臺:

var getGlobal = function () {
    if (typeof self !== 'undefined') { return self; }
    if (typeof window !== 'undefined') { return window; }
    if (typeof global !== 'undefined') { return global; }
    throw new Error('unable to locate global object');
};

但即便這樣也不老是奏效。所以,ES10 添加了 globalThis 對象,從如今開始,該對象用於在任何平臺上訪問全局做用域:

但即便這樣也不老是奏效。所以,ES10 添加了 globalThis 對象,從如今開始,該對象用於在任何平臺上訪問全局做用域:

clipboard.png

總結

JS 是一種動態語言,這對 web 開發很是有益。自 2015 年 ES6 出現以來,JS 語言經歷了一次充滿活力的演變。在這篇文章中,我們回顧了ES10(2019)中出現的特性,並介紹了一些將在ES11(2020)中保持穩定的特性,由於它們處於state 3,而且極可能在下一個版本中被標準化。

儘管這些特性中的許多對於Web應用程序的開發可能不是必需的,可是一些特性能夠規制我們之前經過技巧或大量冗長實現的代碼。

代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug

原文:https://dev.to/carlillo/12-es...

業餘時間都花在整理文章上了,挺苦的,不知道有沒有讚揚買個雞腿的。

clipboard.png

交流

阿里雲最近在作活動,低至2折,有興趣能夠看看:https://promotion.aliyun.com/...

乾貨系列文章彙總以下,以爲不錯點個Star,歡迎 加羣 互相學習。

https://github.com/qq44924588...

由於篇幅的限制,今天的分享只到這裏。若是你們想了解更多的內容的話,能夠去掃一掃每篇文章最下面的二維碼,而後關注我們的微信公衆號,瞭解更多的資訊和有價值的內容。

clipboard.png

相關文章
相關標籤/搜索