摘要:定期召開會議,會議由會員公司的代表與特邀專家出席。新版本將會包含每年截止時間之前完成的所有特性。它引入了一個新的構造函數和具有輔助函數的命名空間對象。
導言:ECMAScript的演化不會停止,但是我們完全沒必要害怕。除了ES6這個史無前例的版本帶來了海量的信息和知識點以外,之后每年一發的版本都僅僅帶有少量的增量更新,一年更新的東西花半個小時就能搞懂了,完全沒必要畏懼。本文將帶您花大約一個小時左右的時間,迅速過一遍ES7,ES8,ES9的新特性。
想追求更好的閱讀體驗,請移步原文地址
題記:本文提供了一個在線PPT版本,方便您瀏覽 細解JAVASCRIPT ES7 ES8 ES9 新特性 在線PPT ver
本文的大部分內容譯自作者Axel Rauschmayer博士的網站,想了解更多關于作者的信息,可以瀏覽Exploring JS: JavaScript books for programmers
那些與ECMAScript有關的事情 誰在設計ECMAScript?TC39 (Technical Committee 39)。
TC39 是推進 JavaScript 發展的委員會。其會員都是公司(其中主要是瀏覽器廠商)。TC39 定期召開會議,會議由會員公司的代表與特邀專家出席。會議紀錄都可在網上查看,可以讓你對 TC39 如何工作有一個清晰的概念。
很有意思的是,TC39 實行的是協商一致的原則:通過一項決議必須得到每一位會員(公司代表)的贊成。
ECMAScript的發布周期在2015年發布的 ECMAScript(ES6)新增內容很多,在 ES5 發布近 6 年(2009-11 至 2015-6)之后才將其標準化。兩個發布版本之間時間跨度如此之大主要有兩大原因:
比新版率先完成的特性,必須等待新版的完成才能發布。
那些需要花長時間完成的特性,也頂著很大的壓力被納入這一版本,因為如果推遲到下一版本發布意味著又要等很久,這種特性也會推遲新的發布版本。
因此,從 ECMAScript 2016(ES7)開始,版本發布變得更加頻繁,每年發布一個新版本,這么一來新增內容也會更小。新版本將會包含每年截止時間之前完成的所有特性。
ECMAScript的發布流程每個 ECMAScript 特性的建議將會從階段 0 開始, 然后經過下列幾個成熟階段。其中從一個階段到下一個階段必須經過 TC39 的批準。
stage-0 - Strawman: just an idea, possible Babel plugin.
任何討論、想法、改變或者還沒加到提案的特性都在這個階段。只有TC39成員可以提交。
當前的stage 0列表可以查看這里 --> Stage 0 Proposals
stage-1 - Proposal: this is worth working on.
什么是 Proposal?一份新特性的正式建議文檔。提案必須指明此建議的潛在問題,例如與其他特性之間的關聯,實現難點等。
stage-2 - Draft: initial spec.
什么是 Draft?草案是規范的第一個版本。其與最終標準中包含的特性不會有太大差別。
草案之后,原則上只接受增量修改。這個階段開始實驗如何實現,實現形式包括polyfill, 實現引擎(提供草案執行本地支持),或者編譯轉換(例如babel)
stage-3 - Candidate: complete spec and initial browser implementations.
候選階段,獲得具體實現和用戶的反饋。此后,只有在實現和使用過程中出現了重大問題才會修改。至少要在一個瀏覽器中實現,提供polyfill或者babel插件。
stage-4 - Finished: will be added to the next yearly release.
已經準備就緒,該特性會出現在下個版本的ECMAScript規范之中。
當前的stage 1-3列表可以查看這里 --> ECMAScript proposals
已經正式發布的特性索引Proposal | Author | Champion(s) | TC39 meeting notes | Expected Publication Year |
---|---|---|---|---|
Array.prototype.includes | Domenic Denicola | Domenic Denicola Rick Waldron |
November 2015 | 2016 |
Exponentiation operator | Rick Waldron | Rick Waldron | January 2016 | 2016 |
Object.values/Object.entries | Jordan Harband | Jordan Harband | March 2016 | 2017 |
String padding | Jordan Harband | Jordan Harband Rick Waldron |
May 2016 | 2017 |
Object.getOwnPropertyDescriptors | Jordan Harband Andrea Giammarchi |
Jordan Harband Andrea Giammarchi |
May 2016 | 2017 |
Trailing commas in function parameter lists and calls | Jeff Morrison | Jeff Morrison | July 2016 | 2017 |
Async functions | Brian Terlson | Brian Terlson | July 2016 | 2017 |
Shared memory and atomics | Lars T Hansen | Lars T Hansen | January 2017 | 2017 |
Lifting template literal restriction | Tim Disney | Tim Disney | March 2017 | 2018 |
s (dotAll) flag for regular expressions | Mathias Bynens | Brian Terlson Mathias Bynens |
November 2017 | 2018 |
RegExp named capture groups | Gorkem Yakin Daniel Ehrenberg |
Daniel Ehrenberg Brian Terlson Mathias Bynens |
November 2017 | 2018 |
Rest/Spread Properties | Sebastian Markb?ge | Sebastian Markb?ge | January 2018 | 2018 |
RegExp Lookbehind Assertions | Gorkem Yakin Nozomu Katō Daniel Ehrenberg |
Daniel Ehrenberg Mathias Bynens |
January 2018 | 2018 |
RegExp Unicode Property Escapes | Mathias Bynens | Brian Terlson Daniel Ehrenberg Mathias Bynens |
January 2018 | 2018 |
Promise.prototype.finally | Jordan Harband | Jordan Harband | January 2018 | 2018 |
Asynchronous Iteration | Domenic Denicola | Domenic Denicola | January 2018 | 2018 |
Optional catch binding | Michael Ficarra | Michael Ficarra | May 2018 | 2019 |
JSON superset | Richard Gibson | Mark Miller Mathias Bynens |
May 2018 | 2019 |
ES7在ES6的基礎上主要添加了兩項內容:
Array.prototype.includes()方法
求冪運算符(**)
Array.prototype.includes()方法includes() 方法用來判斷一個數組是否包含一個指定的值,根據情況,如果包含則返回 true,否則返回false。
var array = [1, 2, 3]; console.log(array.includes(2)); // expected output: true var pets = ["cat", "dog", "bat"]; console.log(pets.includes("cat")); // expected output: true console.log(pets.includes("at")); // expected output: false
Array.prototype.includes()方法接收兩個參數:
要搜索的值
搜索的開始索引。
當第二個參數被傳入時,該方法會從索引處開始往后搜索(默認索引值為0)。若搜索值在數組中存在則返回true,否則返回false。 且看下面示例:
["a", "b", "c", "d"].includes("b") // true ["a", "b", "c", "d"].includes("b", 1) // true ["a", "b", "c", "d"].includes("b", 2) // false
乍一看,includes的作用跟數組的indexOf重疊,為什么要特意增加這么一個api呢?主要區別有以下幾點:
返回值。看一個函數,先看他們的返回值。indexOf的返回數是值型的,includes的返回值是布爾型,所以在if條件判斷的時候includes要簡單得多,而indexOf 需要多寫一個條件進行判斷。
var ary = [1]; if (ary.indexOf(1) !== -1) { console.log("數組存在1") } if (ary.includes(1)) { console.log("數組存在1") }
NaN的判斷。如果數組中有NaN,你又正好需要判斷數組是否有存在NaN,這時你使用indexOf是無法判斷的,你必須使用includes這個方法。
var ary1 = [NaN]; console.log(ary1.indexOf(NaN))//-1 console.log(ary1.includes(NaN))//true
當數組的有空的值的時候,includes會認為空的值是undefined,而indexOf不會。
var ary1 = new Array(3); console.log(ary1.indexOf(undefined));//-1 console.log(ary1.includes(undefined))//true求冪運算符(**)
加/減法我們通常都是用其中綴形式,直觀易懂。在ECMAScript2016中,我們可以使用**來替代Math.pow。
4 ** 3 // 64
效果等同于
Math.pow(4,3)
值得一提的是,作為中綴運算符,**還支持以下操作
let n = 4; n **= 3; // 64ES8新特性(ECMAScript 2017)
在2017年1月的TC39會議上,ECMAScript 2017的最后一個功能“Shared memory and atomics”推進到第4階段。這意味著它的功能集現已完成。
ECMAScript 2017特性一覽
主要新功能:
異步函數 Async Functions(Brian Terlson)
共享內存和Atomics(Lars T. Hansen)
次要新功能:
Object.values / Object.entries(Jordan Harband)
String padding(Jordan Harband,Rick Waldron)
Object.getOwnPropertyDescriptors() (Jordan Harband,Andrea Giammarchi)
函數參數列表和調用中的尾逗號(Jeff Morrison)
Async FunctionsAsync Functions也就是我們常說的Async/Await,相信大家對于這個概念都已經不陌生了。Async/Await是一種用于處理JS異步操作的語法糖,可以幫助我們擺脫回調地獄,編寫更加優雅的代碼。
通俗的理解,async關鍵字的作用是告訴編譯器對于標定的函數要區別對待。當編譯器遇到標定的函數中的await關鍵字時,要暫時停止運行,帶到await標定的函數處理完畢后,再進行相應操作。如果該函數fulfiled了,則返回值是fulfillment 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 = await otherAsyncFunc1(); console.log(result1); const result2 = await otherAsyncFunc2(); console.log(result2); } // Equivalent to: function asyncFunc() { return otherAsyncFunc1() .then(result1 => { console.log(result1); return otherAsyncFunc2(); }) .then(result2 => { console.log(result2); }); }
并行處理多個異步函數:
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); }); }
Async Functions若是要展開去講,可以占用很大段的篇幅。鑒于本文是一篇介紹性文章,再次不再進行深入。
SharedArrayBuffer和Atomics注,如果之前您沒有接觸過ArrayBuffer相關知識的話,建議您從內存管理速成教程系列漫畫解說入門,強推:
A crash course in memory management
[A cartoon intro to ArrayBuffers and SharedArrayBuffers
](https://hacks.mozilla.org/201...
[Avoiding race conditions in SharedArrayBuffers with Atomics
](https://hacks.mozilla.org/201...
ECMAScript 2017 特性 SharedArrayBuffer 和 atomics”,由Lars T. Hansen設計。它引入了一個新的構造函數 SharedArrayBuffer 和 具有輔助函數的命名空間對象 Atomics。
在我們開始之前,讓我們澄清兩個相似但截然不同的術語:并行(Parallelism) 和 并發(Concurrency) 。他們存在許多定義,我使用的定義如下
并行(Parallelism) (parallel 并行 vs. serial 串行):同時執行多個任務;
并發(Concurrency) (concurrent 并發 vs. sequential 連續):在重疊的時間段內(而不是一個接一個)執行幾個任務。
JS并行的歷史JavaScript 在單線程中執行。某些任務可以異步執行:瀏覽器通常會在單線程中運行這些任務,然后通過回調將結果重新加入到單線程中。
Web workers 將任務并行引入了 JavaScript :這些是相對重量級的進程。每個 workers 都有自己的全局環境。默認情況下,不共享任何內容。 workers 之間的通信(或在 workers 和主線程之間的通信)發展:
起初,你只能發送和接收字符串。
然后,引入結構化克隆:可以發送和接收數據副本。結構化克隆適用于大多數數據(JSON 數據,TypedArray,正則表達式,Blob對象,ImageData對象等)。它甚至可以正確處理對象之間的循環引用。但是,不能克隆 error 對象,function 對象和 DOM 節點。
可在 workers 之間的轉移數據:當接收方獲得數據時,發送方失去訪問權限。
通過 WebGL 使用 GPU 計算(它傾向于數據并行處理)
共享數組緩沖區(Shared Array Buffers)共享陣列緩沖區是更高并發抽象的基本構建塊。它們允許您在多個 workers 和主線程之間共享 SharedArrayBuffer 對象的字節(該緩沖區是共享的,用于訪問字節,將其封裝在一個 TypedArray 中)這種共享有兩個好處:
你可以更快地在 workers 之間共享數據。
workers 之間的協調變得更簡單和更快(與 postMessage() 相比)。
// main.js const worker = new Worker("worker.js"); // 要分享的buffer const sharedBuffer = new SharedArrayBuffer( // (A) 10 * Int32Array.BYTES_PER_ELEMENT); // 10 elements // 使用Worker共用sharedBuffer worker.postMessage({sharedBuffer}); // clone // 僅限本地使用 const sharedArray = new Int32Array(sharedBuffer); // (B)
創建一個共享數組緩沖區(Shared Array Buffers)的方法與創建普通的數組緩沖區(Array Buffer)類似:通過調用構造函數,并以字節的形式指定緩沖區的大小(行A)。你與 workers 共享的是 緩沖區(buffer) 。對于你自己的本地使用,你通常將共享數組緩沖區封裝在 TypedArray 中(行B)。
workers的實現如下所列。
// worker.js self.addEventListener("message", function (event) { const {sharedBuffer} = event.data; const sharedArray = new Int32Array(sharedBuffer); // (A) // ··· });sharedArrayBuffer 的 API
構造函數:
new SharedArrayBuffer(length)
創建一個 length 字節的 buffer(緩沖區)。
靜態屬性:
get SharedArrayBuffer[Symbol.species]
默認情況下返回 this。 覆蓋以控制 slice() 的返回。
實例屬性:
get SharedArrayBuffer.prototype.byteLength()
返回 buffer(緩沖區) 的字節長度。
SharedArrayBuffer.prototype.slice(start, end)
創建一個新的 this.constructor[Symbol.species] 實例,并用字節填充從(包括)開始到(不包括)結束的索引。
Atomics: 安全訪問共享數據舉一個例子
// main.js sharedArray[1] = 11; sharedArray[2] = 22;
在單線程中,您可以重新排列這些寫入操作,因為在中間沒有讀到任何內容。 對于多線程,當你期望以特定順序執行寫入操作時,就會遇到麻煩:
// worker.js while (sharedArray[2] !== 22) ; console.log(sharedArray[1]); // 0 or 11
Atomics 方法可以用來與其他 workers 進行同步。例如,以下兩個操作可以讓你讀取和寫入數據,并且不會被編譯器重新排列:
Atomics.load(ta : TypedArray, index)
Atomics.store(ta : TypedArray, index, value : T)
這個想法是使用常規操作讀取和寫入大多數數據,而 Atomics 操作(load ,store 和其他操作)可確保讀取和寫入安全。通常,您將使用自定義同步機制,例如鎖,其實現基于Atomics。
這是一個非常簡單的例子,它總是有效的:
// main.js console.log("notifying..."); Atomics.store(sharedArray, 0, 123); // worker.js while (Atomics.load(sharedArray, 0) !== 123) ; console.log("notified");Atomics 的 API
Atomic 函數的主要操作數必須是 Int8Array ,Uint8Array ,Int16Array ,Uint16Array ,Int32Array 或 Uint32Array 的一個實例。它必須包裹一個 SharedArrayBuffer 。
所有函數都以 atomically 方式進行操作。存儲操作的順序是固定的并且不能由編譯器或 CPU 重新排序。
加載和存儲
Atomics.load(ta : TypedArray
讀取和返回 ta[index] 上的元素,返回數組指定位置上的值。
Atomics.store(ta : TypedArray
在 ta[index] 上寫入 value,并且返回 value。
Atomics.exchange(ta : TypedArray
將 ta[index] 上的元素設置為 value ,并且返回索引 index 原先的值。
Atomics.compareExchange(ta : TypedArray
如果 ta[index] 上的當前元素為 expectedValue , 那么使用 replacementValue 替換。并且返回索引 index 原先(或者未改變)的值。
簡單修改 TypeArray 元素
以下每個函數都會在給定索引處更改 TypeArray 元素:它將一個操作符應用于元素和參數,并將結果寫回元素。它返回元素的原始值。
Atomics.add(ta : TypedArray
執行 ta[index] += value 并返回 ta[index] 的原始值。
Atomics.sub(ta : TypedArray
執行 ta[index] -= value 并返回 ta[index] 的原始值。
Atomics.and(ta : TypedArray
執行 ta[index] &= value 并返回 ta[index] 的原始值。
Atomics.or(ta : TypedArray
執行 ta[index] |= value 并返回 ta[index] 的原始值。
Atomics.xor(ta : TypedArray
執行 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"。否則繼續等待,直到我們通過 Atomics.wake() 喚醒或直到等待超時。 在前一種情況下,返回 "ok"。在后一種情況下,返回"timed-out"。timeout 以毫秒為單位。記住此函數執行的操作:“如果 ta[index] 為 value,那么繼續等待” 。
Atomics.wake(ta : Int32Array, index, count)
喚醒等待在 ta[index] 上的 count workers。
Object.values and Object.entriesObject.values() 方法返回一個給定對象自己的所有可枚舉屬性值的數組,值的順序與使用for...in循環的順序相同 ( 區別在于for-in循環枚舉原型鏈中的屬性 )。
obj參數是需要待操作的對象。可以是一個對象,或者一個數組(是一個帶有數字下標的對象,[10,20,30] -> {0: 10,1: 20,2: 30})。
const obj = { x: "xxx", y: 1 }; Object.values(obj); // ["xxx", 1] const obj = ["e", "s", "8"]; // 相當于 { 0: "e", 1: "s", 2: "8" }; Object.values(obj); // ["e", "s", "8"] // 當我們使用數字鍵值時,返回的是數字排序 // 根據鍵值排序 const obj = { 10: "xxx", 1: "yyy", 3: "zzz" }; Object.values(obj); // ["yyy", "zzz", "xxx"] Object.values("es8"); // ["e", "s", "8"]
Object.entries 方法返回一個給定對象自身可遍歷屬性 [key, value] 的數組, 排序規則和 Object.values 一樣。這個方法的聲明比較瑣碎:
const obj = { x: "xxx", y: 1 }; Object.entries(obj); // [["x", "xxx"], ["y", 1]] 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"]]String padding
為 String 對象增加了 2 個函數:padStart 和 padEnd。
像它們名字那樣,這幾個函數的主要目的就是填補字符串的首部和尾部,為了使得到的結果字符串的長度能達到給定的長度。你可以通過特定的字符,或者字符串,或者默認的空格填充它。下面是函數的聲明:
str.padStart(targetLength [, padString]) str.padEnd(targetLength [, padString])
這些函數的第一個參數是 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"Object.getOwnPropertyDescriptors
getOwnPropertyDescriptors 方法返回指定對象所有自身屬性的描述對象。屬性描述對象是直接在對象上定義的,而不是繼承于對象的原型。ES2017加入這個函數的主要動機在于方便將一個對象深度拷貝給另一個對象,同時可以將getter/setter拷貝。聲明如下:
Object.getOwnPropertyDescriptors(obj)
obj 是待操作對象。返回的描述對象鍵值有:configurable, enumerable, writable, get, set and value。
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 // } // }結尾逗號
結尾逗號用代碼展示非常明了:
// 參數定義時 function foo( param1, param2, ) {} // 函數調用時 foo( "abc", "def", ); // 對象中 let obj = { first: "Jane", last: "Doe", }; // 數組中 let arr = [ "red", "green", "blue", ];
這個改動有什么好處呢?
首先,重新排列項目更簡單,因為如果最后一項更改其位置,則不必添加和刪除逗號。
其次,它可以幫助版本控制系統跟蹤實際發生的變化。例如,從:
[ "foo" ]
修改為
[ "foo", "bar" ]
導致線條"foo"和線條"bar"被標記為已更改,即使唯一真正的變化是后一條線被添加。
ES9新特性(ECMAScript 2018)ES9的新特性索引如下:
主要新功能:
異步迭代(Domenic Denicola,Kevin Smith)
Rest/Spread 屬性(SebastianMarkb?ge)
新的正則表達式功能:
RegExp named capture groups(Gorkem Yakin,Daniel Ehrenberg)
RegExp Unicode Property Escapes(Mathias Bynens)
RegExp Lookbehind Assertions(Gorkem Yakin,NozomuKatō,Daniel Ehrenberg)
s (dotAll) flag for regular expressions(Mathias Bynens)
其他新功能:
Promise.prototype.finally() (Jordan Harband)
模板字符串修改(Tim Disney)
異步迭代 首先來回顧一下同步迭代器:ES6引入了同步迭代器,其工作原理如下:
Iterable:一個對象,表示可以通過Symbol.iterator方法進行迭代。
Iterator:通過調用iterable [Symbol.iterator] ()返回的對象。它將每個迭代元素包裝在一個對象中,并通過其next()方法一次返回一個。
IteratorResult:返回的對象next()。屬性value包含一個迭代的元素,屬性done是true 后最后一個元素。
示例:
const iterable = ["a", "b"]; const iterator = iterable[Symbol.iterator](); iterator.next() // { value: "a", done: false } iterator.next() // { value: "b", done: false } iterator.next() // { value: undefined, done: true }異步迭代器
先前的迭代方式是同步的,并不適用于異步數據源。例如,在以下代碼中,readLinesFromFile()無法通過同步迭代傳遞其異步數據:
for (const line of readLinesFromFile(fileName)) { console.log(line); }
異步迭代器和常規迭代器的工作方式非常相似,但是異步迭代器涉及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} }
異步迭代器對象的next()方法返回了一個Promise,解析后的值跟普通的迭代器類似。
用法:iterator.next().then(({ value, done })=> {//{value: ‘some val’, done: false}}
const promises = [ new Promise(resolve => resolve(1)), new Promise(resolve => resolve(2)), new Promise(resolve => resolve(3)), ]; async function test() { for await (const p of promises) { console.log(p); } } test(); //1 ,2 3Rest/Spread 屬性
這個就是我們通常所說的rest參數和擴展運算符,這項特性在ES6中已經引入,但是ES6中的作用對象僅限于數組:
restParam(1, 2, 3, 4, 5); function restParam(p1, p2, ...p3) { // p1 = 1 // p2 = 2 // p3 = [3, 4, 5] } const values = [99, 100, -1, 48, 16]; console.log( Math.max(...values) ); // 100
在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} }正則表達式命名捕獲組 編號的捕獲組
//正則表達式命名捕獲組 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
通過數字引用捕獲組有幾個缺點:
找到捕獲組的數量是一件麻煩事:必須使用括號。
如果要了解組的用途,則需要查看正則表達式。
如果更改捕獲組的順序,則還必須更改匹配代碼。
命名的捕獲組ES9中可以通過名稱來識別捕獲組:(?
在這里,我們用名稱標記了前一個捕獲組year。該名稱必須是合法的JavaScript標識符(認為變量名稱或屬性名稱)。匹配后,您可以通過訪問捕獲的字符串matchObj.groups.year來訪問。
讓我們重寫前面的代碼:
const RE_DATE = /(?[0-9]{4})-(? [0-9]{2})-(? [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.day; // 31 // 使用解構語法更為簡便 const {groups: {day, year}} = RE_DATE.exec("1999-12-31"); console.log(year); // 1999 console.log(day); // 31
可以發現,命名捕獲組有以下優點:
找到捕獲組的“ID”更容易。
匹配代碼變為自描述性的,因為捕獲組的ID描述了正在捕獲的內容。
如果更改捕獲組的順序,則無需更改匹配代碼。
捕獲組的名稱也使正則表達式更容易理解,因為您可以直接看到每個組的用途。
正則表達式 Unicode 轉義該特性允許您使用p{}通過提及大括號內的Unicode字符屬性來匹配字符,在正則表達式中使用標記 u (unicode) 設置。
/^p{White_Space}+$/u.test(" ") // true /^p{Script=Greek}+$/u.test("μετ?") // true新方法匹配中文字符
由于在Unicode里面,中文字符對應的Unicode Script是Han,于是我們就可以用這個reg來匹配中文:
/p{Script=Han}/u
這樣我們就可以不用記憶繁瑣又不好記的/[u4e00-u9fa5]/了,況且這個表達式已經有些年頭了,說實話,后來又新增的屬性為Han的字符并不在這個范圍內,因此這個有年頭reg并不一定好使。
我隨便從網上找了一個Unicode8.0添加的中文字符“
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/99498.html
摘要:規范最終由敲定。提案由至少一名成員倡導的正式提案文件,該文件包括事例。箭頭函數這是中最令人激動的特性之一。數組拷貝等同于展開語法和行為一致執行的都是淺拷貝只遍歷一層。不使用對象中必須包含屬性和值,顯得非常冗余。 ES全稱ECMAScript,ECMAScript是ECMA制定的標準化腳本語言。目前JavaScript使用的ECMAScript版本為ECMA-417。關于ECMA的最新資訊可以...
摘要:字符串拓展在我們判斷字符串是否包含另一個字符串時,之前,我們只有方法,之后我們又多了三種方法返回布爾值,表示是否找到參數字符串。返回布爾值,表示參數字符串是否在原字符串的頭部。 本文是 重溫基礎 系列文章的第八篇。今日感受:人在異鄉,也不能忘記湯圓。 系列目錄: 【復習資料】ES6/ES7/ES8/ES9資料整理(個人整理) 【重溫基礎】1.語法和數據類型 【重溫基礎】2.流程控制和...
摘要:歡迎您的支持系列目錄復習資料資料整理個人整理重溫基礎篇重溫基礎對象介紹重溫基礎對象介紹重溫基礎介紹重溫基礎相等性判斷重溫基礎閉包重溫基礎事件本章節復習的是中的高階函數,可以提高我們的開發效率。 本文是 重溫基礎 系列文章的第二十一篇。 今日感受:想家。 本人自己整理的【Cute-JavaScript】資料,包含:【ES6/ES7/ES8/ES9】,【JavaScript基礎...
摘要:我曾寫過一篇關于博客個最佳特性,這次我打算聊聊和特性。自從年雙十一正式上線,累計處理了億錯誤事件,得到了金山軟件百姓網等眾多知名用戶的認可。 譯者按: 轉眼ES6發布2年了,是時候了解一下ES7與ES8特性了! 原文: ES7 and ES8 Features 譯者: Fundebug 為了保證可讀性,本文采用意譯而非直譯,并且對源代碼進行了大量修改。另外,本文版權歸原作者所有...
摘要:本文是重溫基礎系列文章的第十二篇。注意對象的名稱,對大小寫敏感。基礎用法第一個參數是目標對象,后面參數都是源對象。用途遍歷對象屬性。用途將對象轉為真正的結構。使用場景取出參數對象所有可遍歷屬性,拷貝到當前對象中。類似方法合并兩個對象。 本文是 重溫基礎 系列文章的第十二篇。 今日感受:需要總結下2018。 這幾天,重重的感冒發燒,在家休息好幾天,傷···。 系列目錄: 【復習資料...
閱讀 2517·2021-09-09 09:33
閱讀 2877·2019-08-30 15:56
閱讀 3162·2019-08-30 14:21
閱讀 913·2019-08-30 13:01
閱讀 877·2019-08-26 18:27
閱讀 3596·2019-08-26 13:47
閱讀 3467·2019-08-26 10:26
閱讀 1600·2019-08-23 18:38