導言:ECMAScript的演化不會中止,可是咱們徹底不必懼怕。除了ES6這個前所未有的版本帶來了海量的信息和知識點之外,以後每一年一發的版本都僅僅帶有少許的增量更新,一年更新的東西花半個小時就能搞懂了,徹底不必畏懼。本文將帶您花大約一個小時左右的時間,迅速過一遍ES7,ES8,ES9的新特性。javascript
想追求更好的閱讀體驗,請移步原文地址java
題記:本文提供了一個在線PPT版本,方便您瀏覽 細解JAVASCRIPT ES7 ES8 ES9 新特性 在線PPT vergit
本文的大部份內容譯自做者Axel Rauschmayer博士的網站,想了解更多關於做者的信息,能夠瀏覽Exploring JS: JavaScript books for programmersgithub
TC39 (Technical Committee 39)。正則表達式
TC39 是推動 JavaScript 發展的委員會。其會員都是公司(其中主要是瀏覽器廠商)。TC39 按期召開會議,會議由會員公司的表明與特邀專家出席。會議紀錄均可在網上查看,可讓你對 TC39 如何工做有一個清晰的概念。express
頗有意思的是,TC39 實行的是協商一致的原則:經過一項決議必須獲得每一位會員(公司表明)的同意。json
在2015年發佈的 ECMAScript(ES6)新增內容不少,在 ES5 發佈近 6 年(2009-11 至 2015-6)以後纔將其標準化。兩個發佈版本之間時間跨度如此之大主要有兩大緣由:api
所以,從 ECMAScript 2016(ES7)開始,版本發佈變得更加頻繁,每一年發佈一個新版本,這麼一來新增內容也會更小。新版本將會包含每一年截止時間以前完成的全部特性。數組
每一個 ECMAScript 特性的建議將會從階段 0 開始, 而後通過下列幾個成熟階段。其中從一個階段到下一個階段必須通過 TC39 的批准。promise
當前的stage 0列表能夠查看這裏 --> Stage 0 Proposals
什麼是 Proposal?一份新特性的正式建議文檔。提案必須指明此建議的潛在問題,例如與其餘特性之間的關聯,實現難點等。
什麼是 Draft?草案是規範的第一個版本。其與最終標準中包含的特性不會有太大差異。
草案以後,原則上只接受增量修改。這個階段開始實驗如何實現,實現形式包括polyfill, 實現引擎(提供草案執行本地支持),或者編譯轉換(例如babel)
候選階段,得到具體實現和用戶的反饋。此後,只有在實現和使用過程當中出現了重大問題纔會修改。至少要在一個瀏覽器中實現,提供polyfill或者babel插件。
已經準備就緒,該特性會出如今下個版本的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的基礎上主要添加了兩項內容:
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呢?主要區別有如下幾點:
var ary = [1]; if (ary.indexOf(1) !== -1) { console.log("數組存在1") } if (ary.includes(1)) { console.log("數組存在1") }
var ary1 = [NaN]; console.log(ary1.indexOf(NaN))//-1 console.log(ary1.includes(NaN))//true
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; // 64
在2017年1月的TC39會議上,ECMAScript 2017的最後一個功能「Shared memory and atomics」推動到第4階段。這意味着它的功能集現已完成。
ECMAScript 2017特性一覽
主要新功能:
次要新功能:
Async 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如果要展開去講,能夠佔用很大段的篇幅。鑑於本文是一篇介紹性文章,再次再也不進行深刻。
注,若是以前您沒有接觸過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) 。他們存在許多定義,我使用的定義以下
Web workers 將任務並行引入了 JavaScript :這些是相對重量級的進程。每一個 workers 都有本身的全局環境。默認狀況下,不共享任何內容。 workers 之間的通訊(或在 workers 和主線程之間的通訊)發展:
共享陣列緩衝區是更高併發抽象的基本構建塊。它們容許您在多個 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) // ··· });
構造函數:
建立一個 length 字節的 buffer(緩衝區)。
靜態屬性:
默認狀況下返回 this。 覆蓋以控制 slice() 的返回。
實例屬性:
返回 buffer(緩衝區) 的字節長度。
建立一個新的 this.constructor[Symbol.species] 實例,並用字節填充從(包括)開始到(不包括)結束的索引。
舉一個例子
// 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 ,store 和其餘操做)可確保讀取和寫入安全。一般,您將使用自定義同步機制,例如鎖,其實現基於Atomics。
這是一個很是簡單的例子,它老是有效的:
// main.js console.log('notifying...'); Atomics.store(sharedArray, 0, 123); // worker.js while (Atomics.load(sharedArray, 0) !== 123) ; console.log('notified');
Atomic 函數的主要操做數必須是 Int8Array ,Uint8Array ,Int16Array ,Uint16Array ,Int32Array 或 Uint32Array 的一個實例。它必須包裹一個 SharedArrayBuffer 。
全部函數都以 atomically 方式進行操做。存儲操做的順序是固定的而且不能由編譯器或 CPU 從新排序。
加載和存儲
讀取和返回 ta[index] 上的元素,返回數組指定位置上的值。
在 ta[index] 上寫入 value,而且返回 value。
將 ta[index] 上的元素設置爲 value ,而且返回索引 index 原先的值。
若是 ta[index] 上的當前元素爲 expectedValue , 那麼使用 replacementValue 替換。而且返回索引 index 原先(或者未改變)的值。
簡單修改 TypeArray 元素
如下每一個函數都會在給定索引處更改 TypeArray 元素:它將一個操做符應用於元素和參數,並將結果寫回元素。它返回元素的原始值。
執行 ta[index] += value 並返回 ta[index] 的原始值。
執行 ta[index] -= value 並返回 ta[index] 的原始值。
執行 ta[index] &= value 並返回 ta[index] 的原始值。
執行 ta[index] |= value 並返回 ta[index] 的原始值。
執行 ta[index] ^= value 並返回 ta[index] 的原始值。
等待和喚醒
若是 ta[index] 的當前值不是 value ,則返回 'not-equal'。不然繼續等待,直到咱們經過 Atomics.wake() 喚醒或直到等待超時。 在前一種狀況下,返回 'ok'。在後一種狀況下,返回'timed-out'。timeout 以毫秒爲單位。記住此函數執行的操做:「若是 ta[index] 爲 value,那麼繼續等待」 。
喚醒等待在 ta[index] 上的 count workers。
Object.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 對象增長了 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'
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的新特性索引以下:
主要新功能:
新的正則表達式功能:
其餘新功能:
ES6引入了同步迭代器,其工做原理以下:
示例:
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 3
這個就是咱們一般所說的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>[0-9]{4})
在這裏,咱們用名稱標記了前一個捕獲組year。該名稱必須是合法的JavaScript標識符(認爲變量名稱或屬性名稱)。匹配後,您能夠經過訪問捕獲的字符串matchObj.groups.year來訪問。
讓咱們重寫前面的代碼:
const RE_DATE = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[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
能夠發現,命名捕獲組有如下優勢:
該特性容許您使用\p{}
經過說起大括號內的Unicode字符屬性來匹配字符,在正則表達式中使用標記 u
(unicode) 設置。
/^\p{White_Space}+$/u.test('\t \n\r') // true /^\p{Script=Greek}+$/u.test('μετά') // true
因爲在Unicode裏面,中文字符對應的Unicode Script是Han,因而咱們就能夠用這個reg來匹配中文:
/\p{Script=Han}/u
這樣咱們就能夠不用記憶繁瑣又很差記的/[\u4e00-\u9fa5]/
了,何況這個表達式已經有些年頭了,說實話,後來又新增的屬性爲Han的字符並不在這個範圍內,所以這個有年頭reg並不必定好使。
我隨便從網上找了一個Unicode8.0添加的中文字符「錀」,我測了一下兩種reg的兼容性:
oldReg=/[\u4e00-\u9fa5]/ newReg=/\p{Script=Han}/u oldReg.test('abc') // false newReg.test('abc') // false oldReg.test('地平線') // true newReg.test('地平線') // true oldReg.test('錀') // false newReg.test('錀') // true
http://www.unicode.org/charts...
能夠參考一下這個PDF,是Unicode的漢字全集,從524頁9FA6至526頁(最後一頁)用舊匹配方式都沒法生效。
Name:惟一名稱,由大寫字母,數字,連字符和空格組成。例如:
General_Category:對字符進行分類。例如:
White_Space:用於標記不可見的間距字符,例如空格,製表符和換行符。例如:
Age:引入字符的Unicode標準版本。例如:歐元符號€在Unicode標準的2.1版中添加。
Script:是一個或多個書寫系統使用的字符集合。
例子:
\p{prop=value}
\P{prop=value}
\p{bin_prop}
\P{bin_prop}
/^\p{White_Space}+$/u.test('\t \n\r') //true
匹配字母:
/^\p{Letter}+$/u.test('πüé') //true
匹配希臘字母:
/^\p{Script=Greek}+$/u.test('μετά') //true
匹配拉丁字母:
/^\p{Script=Latin}+$/u.test('Grüße') //true
先來看下正則表達式先行斷言是什麼:
如獲取貨幣的符號
const noReLookahead = /\D(\d+)/, reLookahead = /\D(?=\d+)/, match1 = noReLookahead.exec('$123.45'), match2 = reLookahead.exec('$123.45'); console.log(match1[0]); // $123 console.log(match2[0]); // $
在ES9中能夠容許反向斷言:
const reLookahead = /(?<=\D)[\d\.]+/; match = reLookahead.exec('$123.45'); console.log(match[0]); // 123.45
使用?<=進行反向斷言,可使用反向斷言獲取貨幣的價格,而忽略貨幣符號。
正則表達式中點.匹配除回車外的任何單字符,標記s改變這種行爲,容許行終止符的出現,例如:
/hello.world/.test('hello\nworld'); // false /hello.world/s.test('hello\nworld'); // true
這個基本沒什麼好講的,看名字就能看懂了。其用法以下:
promise .then(result => {···}) .catch(error => {···}) .finally(() => {···});
finally的回調總會被執行。
ES2018 移除對 ECMAScript 在帶標籤的模版字符串中轉義序列的語法限制。
以前,u開始一個 unicode 轉義,x開始一個十六進制轉義,後跟一個數字開始一個八進制轉義。這使得建立特定的字符串變得不可能,例如Windows文件路徑 C:uuuxxx111。
要取消轉義序列的語法限制,可在模板字符串以前使用標記函數String.raw:
`\u{54}` // "T" String.raw`\u{54}` // "\u{54}"
ECMAScript的演化不會中止,可是咱們徹底不必懼怕。除了ES6這個前所未有的版本帶來了海量的信息和知識點之外,以後每一年一發的版本都僅僅帶有少許的增量更新,一年更新的東西花半個小時就能搞懂了,徹底不必畏懼。
Stay hungry. Stay foolish.