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