阿里雲最近在作活動,低至2折,有興趣能夠看看:
https://promotion.aliyun.com/...
爲了保證的可讀性,本文采用意譯而非直譯。css
想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等着你!html
跟蹤JavaScript (ECMAScript)中的新內容是很困難的,並且更難找到有用的代碼示例。前端
所以,在本文中將介紹 TC39(最終草案) 在ES201六、ES2017和ES2018中添加的已完成提案中列出的全部18個特性,並給出有用的示例。git
include 是數組上的一個簡單實例方法,能夠輕鬆查找數組中是否有指定內容(包括 NaN)。github
像加法和減法這樣的數學運算分別有像 + 和 - 這樣運算符。與它們相似,**
運算符一般用於指數運算。在ECMAScript 2016中,引入了 **
代替 Math.pow。web
Object.values()是一個相似於Object.keys()的新函數,但返回對象自身屬性的全部值,不包括原型鏈中的任何值。正則表達式
Object.entries()與Object.keys 相似,但它不是僅返回鍵,而是以數組方式返回鍵和值。 這使得在循環中使用對象或將對象轉換爲映射等操做變得很是簡單。數據庫
例一:segmentfault
例二:數組
在String.prototype中添加了兩個實例方法:String.prototype.padStart 和 String.prototype.padEnd, 容許在初始字符串的開頭或末尾追加/前置空字符串或其餘字符串。
'someString'.padStart(numberOfCharcters [,stringForPadding]); '5'.padStart(10) // ' 5' '5'.padStart(10, '=*') //'=*=*=*=*=5' '5'.padEnd(10) // '5 ' '5'.padEnd(10, '=*') //'5=*=*=*=*='
當咱們想要在漂亮的打印顯示或終端打印進行對齊時,這很是有用。
在下面的例子中,有一個不一樣長度的數字列表。咱們但願在「0」爲追加符讓全部項長度都爲10位,以便顯示,咱們可使用padStart(10, '0')輕鬆實現這一點。
當咱們打印多個不一樣長度的項目並想要右對齊它們時,padEnd很是有用。
下面的示例是關於padEnd、padStart和 Object.entries 的一個很好的實際示例:
const cars = { '🚙BMW': '10', '🚘Tesla': '5', '🚖Lamborghini': '0' } Object.entries(cars).map(([name, count]) => { console.log(`${name.padEnd(20, ' -')} Count: ${count.padStart(3, '0')}`) }) // 打印 // 🚙BMW - - - - - - - Count: 010 // 🚘Tesla - - - - - - Count: 005 // 🚖Lamborghini - - - Count: 000
Emojis和其餘雙字節字符使用多個unicode字節表示。因此padStart padEnd可能不會像預期的那樣工做!⚠️
例如:假設咱們要墊達到10個字符的字符串的心❤️emoji。結果以下:
'heart'.padStart(10, "❤️"); // prints.. '❤️❤️❤heart'
這是由於 ❤️ 長2個字節(' u2764 uFE0F')! 單詞 heart 是5個字符,因此咱們只剩下5個字符來填充。 因此 JS 使用 ('u2764uFE0F' ) 填充兩顆心並生成 ❤️❤️。 對於最後一個,它只使用 ('u2764uFE0F' ) 的第一個字節(u2764)來生成,因此是 ❤;
此方法返回給定對象的全部屬性的全部屬性(包括getter setter set方法),添加這個的主要目的是容許淺 拷貝/克隆到另外一個對象中的對象,相似 bject.assign。
Object.assign 淺拷貝除原始對象的 getter 和 setter 方法以外的全部屬性。
下面的示例顯示了 Object.assign 和 Object.getOwnPropertyDescriptors 以及Object.defineProperties 之間的區別,以將原始對象 Car 複製到新對象 ElectricCar 中。 能夠看到使用 Object.getOwnPropertyDescriptors,discount 的 getter 和 setter 函數也被複制到目標對象中。
使用 Object.defineProperties
var Car = { name: 'BMW', price: 1000000, set discount(x) { this.d = x; }, get discount() { return this.d; }, }; console.log(Object.getOwnPropertyDescriptor(Car, 'discount')); // 打印 // { // get: [Function: get], // set: [Function: set], // enumerable: true, // configurable: true // } // 使用 Object.assign 拷貝對象 const ElectricCar = Object.assign({}, Car); //Print details of ElectricCar object's 'discount' property console.log(Object.getOwnPropertyDescriptor(ElectricCar, 'discount')); // 打印 // { // value: undefined, // writable: true, // enumerable: true, // configurable: true // } // //⚠️請注意,「discount」 屬性的 ElectricCar 對象中缺乏getter和setter!👎👎 //Copy Car's properties to ElectricCar2 using Object.defineProperties //and extract Car's properties using Object.getOwnPropertyDescriptors const ElectricCar2 = Object.defineProperties({}, Object.getOwnPropertyDescriptors(Car)); //Print details of ElectricCar2 object's 'discount' property console.log(Object.getOwnPropertyDescriptor(ElectricCar2, 'discount')); //prints.. // { get: [Function: get], 👈🏼👈🏼👈🏼 // set: [Function: set], 👈🏼👈🏼👈🏼 // enumerable: true, // configurable: true // } // 請注意,在ElectricCar2對象中存在「discount」屬性的getter和setter !
ES2017容許函數的最後一個參數有尾逗號(trailing comma), 此前,函數定義和調用時,都不容許最後一個參數後面出現逗號。這一變化將鼓勵開發人員中止醜陋的「行以逗號開頭」的習慣。這對於版本管理系統來講,就會顯示添加逗號的那一行也發生了變更。
到目前爲止,我的感覺是這是最重要和最有用的功能。 async 函數容許咱們不處理回調地獄,並使整個代碼看起來很簡單。
async 關鍵字告訴 JavaScript 編譯器以不一樣的方式對待函數。每當編譯器到達函數中的 await 關鍵字時,它就會暫停。它假定 wait 以後的表達式返回一個 promise ,並在進一步移動以前等待該 promise 被 resolved 或 rejected。
在下面的示例中,getAmount 函數調用兩個異步函數getUser和getBankBalance。使用 async await更加優雅和簡單達到有有序的調用 getUser 與 getBankBalance。
若是您正在等待 async 函數的結果,則須要使用 Promise 的 then 語法來捕獲其結果。
在如下示例中,咱們但願使用 console.log 來打印結果可是不在 doubleAndAdd 函數裏面操做。 由於 async 返回是一個 promise 對象,因此能夠在 then 裏面執行咱們一些打印操做。
在前面的例子中,咱們調用doubleAfterlSec ,但每次咱們等待一秒鐘(總共2秒)。 相反,咱們可使用 Promise.all 將它並行化爲一個而且互不依賴於。
在使用async/wait時,有多種方法能夠處理錯誤。
方法一:在函數內使用 try catch
async function doubleAndAdd(a, b) { try { a = await doubleAfter1Sec(a); b = await doubleAfter1Sec(b); } catch (e) { return NaN; //return something } return a + b; } doubleAndAdd('one', 2).then(console.log); // NaN doubleAndAdd(1, 2).then(console.log); // 6 function doubleAfter1Sec(param) { return new Promise((resolve, reject) => { setTimeout(function() { let val = param * 2; isNaN(val) ? reject(NaN) : resolve(val); }, 1000); }); }
方法二:在 await 後使用 catch 捕獲錯誤
// 方法二:在 await 後使用 catch 獲取錯誤 async function doubleAndAdd(a, b) { a = await doubleAfter1Sec(a).catch(e => console.log('"a" is NaN')); // 👈 b = await doubleAfter1Sec(b).catch(e => console.log('"b" is NaN')); // 👈 if (!a || !b) { return NaN; } return a + b; } doubleAndAdd('one', 2).then(console.log); // NaN and logs: "a" is NaN doubleAndAdd(1, 2).then(console.log); // 6 function doubleAfter1Sec(param) { return new Promise((resolve, reject) => { setTimeout(function() { let val = param * 2; isNaN(val) ? reject(NaN) : resolve(val); }, 1000); }); }
方法三:在整個的 async-await 函數捕獲錯誤
//方法三:在整個的 async-await 函數捕獲錯誤 async function doubleAndAdd(a, b) { a = await doubleAfter1Sec(a); b = await doubleAfter1Sec(b); return a + b; } doubleAndAdd('one', 2) .then(console.log) .catch(console.log); // 👈👈🏼<------- use "catch" function doubleAfter1Sec(param) { return new Promise((resolve, reject) => { setTimeout(function() { let val = param * 2; isNaN(val) ? reject(NaN) : resolve(val); }, 1000); }); }
這是一個巨大的、至關高級的特性,是JS引擎的核心加強。
其主要原理是在 JavaScript 中引入某種多線程特性,以便JS開發人員未來能夠經過容許本身管理內存而不是讓 JS 引擎管理內存來編寫高性能的併發程序。
這是經過一種名爲 SharedArrayBuffer (即 共享數組緩衝區) 的新類型的全局對象實現的,該對象本質上是將數據存儲在共享內存空間中。所以,這些數據能夠在主JS線程和web工做線程之間共享。
到目前爲止,若是咱們想在主 JS 線程和 web 工做者之間共享數據,咱們必須複製數據並使用postMessage 將其發送到另外一個線程。
你只需使用SharedArrayBuffer,數據就能夠當即被主線程和多個web工做線程訪問。workers 之間的協調變得更簡單和更快(與 postMessage() 相比)。
可是在線程之間共享內存會致使競爭條件。爲了幫助避免競爭條件,引入了 「Atomics」 全局對象。 Atomics 提供了各類方法來在線程使用其數據時鎖定共享內存。 它還提供了安全地更新該共享內存中的搜索數據的方法。
若是你這對個感興趣,能夠閱讀如下文章:
首先,咱們須要知道的什麼是 Template literals(「標記的模板文字」),以便更好地理解這個特性。Template literals是一個ES2015特性,它使用反引號包含一個字符串字面量,而且支持嵌入表達式和換行,如:
下面的例子顯示,咱們的自定義「Tag」 函數 greet 添加了一天中的時間,好比「Good Morning!」 「Good afternoon」 等等,取決於一天中的時間字符串的文字和返回自定義字符串。
function greet(hardCodedPartsArray, ...replacementPartsArray) { console.log(hardCodedPartsArray); //[ 'Hello ', '!' ] console.log(replacementPartsArray); //[ 'Raja' ] let str = ''; hardCodedPartsArray.forEach((string, i) => { if (i < replacementPartsArray.length) { str += `${string} ${replacementPartsArray[i] || ''}`; } else { str += `${string} ${timeGreet()}`; //<-- 追加 Good morning/afternoon/evening here } }); return str; } const firstName = 'Raja'; const greetings = greet`Hello ${firstName}!`; //👈🏼<-- Tagged literal console.log(greetings); //'Hello Raja! Good Morning!' 🔥 function timeGreet() { const hr = new Date().getHours(); return hr < 12 ? 'Good Morning!' : hr < 18 ? 'Good Afternoon!' : 'Good Evening!'; }
如今咱們討論了什麼是「標記」函數,許多人但願在不一樣的領域中使用這個特性,好比在Terminal中用於命令,在組成 uri 的 HTTP 請求中,等等。
⚠️ 帶標記字符串文字的問題
問題是ES2015和ES2016規範不容許使用像「u」(unicode)、「x」(十六進制)這樣的轉義字符,除非它們看起來徹底像「 u00A9」或u{2F804}或xA9。
所以,若是你有一個內部使用其餘域規則(如終端規則)的標記函數,可能須要使用看起來不像 u0049或 u {@ F804}的 ubla123abla,那麼你會獲得一個語法錯誤,
function myTagFunc(str) { return { "cooked": "undefined", "raw": str.raw[0] } } var str = myTagFunc `hi \ubla123abla`; //call myTagFunc str // { cooked: "undefined", raw: "hi \\unicode" }
目前在正則表達式中,雖然點(「.」)應該匹配單個字符,但它不匹配像 n r f 等新行字符。
例如:
//Before /first.second/.test('first\nsecond'); //false
這種加強使 點 運算符可以匹配任何單個字符。爲了確保它不會破壞任何東西,咱們須要在建立正則表達式時使用s標誌。
//ECMAScript 2018 /first.second/s.test('first\nsecond'); //true Notice: /s 👈🏼
更多的方法,請看這裏:
這種加強 RegExp特性借鑑於像Python、Java等其餘語言,所以稱爲「命名組」。這個特性容許編寫開發人員以(<name>…)格式爲 RegExp 中的組的不一樣部分提供名稱(標識符),使用能夠用這個名稱輕鬆地獲取他們須要的任何組。
在下面的示例中,咱們使用 (?<year>) (?<month>) 和 (?<day>) 名稱對日期正則表達式的不一樣部分進行分組。結果對象如今將包含一個groups屬性,該屬性具備 year、month和 day 的相應值。
let re1 = /(\d{4})-(\d{2})-(\d{2})/; let result1 = re1.exec('2015-01-02'); console.log(result1); // [ '2015-01-02', '2015', '01', '02', index: 0, input: '2015-01-02' ] // ECMAScript 2018 let re2 = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u; let result2 = re2.exec('2015-01-02'); console.log(result2); // ["2015-01-02", "2015", "01", "02", index: 0, input: "2015-01-02", // groups: {year: "2015", month: "01", day: "02"} // ] console.log(result2.groups.year); // 2015
使用\k<組名>
格式來反向引用正則表達式自己中的組,例如:
// 在下面的例子中,咱們有一個包合的「水果」組。 // 它既能夠配「蘋果」,也能夠配「橘子」, // 咱們可使用 「\k<group name>」 (\k<fruit>) 來反向引用這個組的結果, // 因此它能夠匹配「=」相同的單詞 let sameWords = /(?<fruit>apple|orange)=\k<fruit>/u; sameWords.test('apple=apple') // true sameWords.test('orange=orange') // true sameWords.test('apple=orange') // false
在 String.prototype.replace 方法中使用 named groups。因此咱們能更快捷的交換詞。
例如,把 「firstName, lastName」 改爲 「lastName, firstName」。
let re = /(?<firstName>[A-Za-z]+) (?<lastName>[A-Za-z]+$)/u; 'Hello World'.replace(re, `$<lastName>, $<firstName>`) // "World, Hello"
rest操做 …(三個點)容許挑練咱們須要的屬性。
let { firstName, age, ...remaining } = { firstName: '王', lastName: '智藝', age: 27, height: '1.78', race: '黃' } firstName; // 王 age; // 27 remaining; // { lastName: "智藝", height: "1.78", race: "黃" }
擴展 和 解析 的 三個點是同樣的,可是不一樣的是你能夠用 擴展
去新建或者組合一個新對象。
擴展
是對齊賦值的右運算符, 而解構
是左運算符。
const person = { fName: '小明', age: 20 }; const account = { name: '小智', amount: '$1000'}; const personAndAccount = { ...person, ...account }; personAndAccount; // {fName: "小明", age: 20, name: "小智", amount: "$1000"}
斷言(Assertion)是一個對當前匹配位置以前或以後的字符的測試, 它不會實際消耗任何字符,因此斷言也被稱爲「非消耗性匹配」或「非獲取匹配」。
正則表達式的斷言一共有 4 種形式:
你可使用組(?<=…) 去正向斷言,也能夠用 (?<!…) 去取反。
正向斷言: 咱們想確保 # 在 winning 以前。(就是#winning),想正則匹配返回 winning。下面是寫法:
反向斷言:匹配一個數字,有 € 字符而沒有 $ 字符在前面的數字。
更多內容能夠參考:S2018 新特徵之:正則表達式反向(lookbehind)斷言
用正則去匹配 Unicode 字符是很不容易的。像 w , W , d 這種只能匹配英文字符和數字。可是其餘語言的字符怎麼辦呢,好比印度語,希臘語?
例如 Unicode 數據庫組裏把全部的印度語字符,標識爲 Script = Devanagari。還有一個屬性 Script_Extensions, 值也爲 Devanagari。 因此咱們能夠經過搜索 Script=Devanagari,獲得全部的印度語。
Devanagari 能夠用於印度的各類語言,如Marathi, Hindi, Sanskrit。
在 ECMAScript 2018 裏, 咱們可使用 p 和 {Script=Devanagari} 匹配那些全部的印度語字符。也就是說 p{Script=Devanagari} 這樣就能夠匹配。
//The following matches multiple hindi character /^\p{Script=Devanagari}+$/u.test('हिन्दी'); //true //PS:there are 3 hindi characters h
同理,希臘語的語言是 Script_Extensions 和 Script 的值等於 Greek 。也就是用Script_Extensions=Greek or Script=Greek 這樣就能夠匹配全部的希臘語,也就是說,咱們用 p{Script=Greek} 匹配全部的希臘語。
進一步說,Unicode 表情庫裏存了各式各樣的布爾值,像 Emoji, Emoji_Component, Emoji_Presentation, Emoji_Modifier, and Emoji_Modifier_Base
的值,都等於 true。因此咱們想搜 Emoji 等於 ture,就能搜到全部的表情。
咱們用 \p{Emoji} ,\Emoji_Modifier
匹配全部的表情。
參考文獻:
finally()
是 Promise 新增的一個實例方法。意圖是容許在 resolve/reject 以後執行回調。finally 沒有返回值,始終會被執行。
讓咱們看看各類狀況。
這是一個極其好用的新特性。讓咱們可以很是容易的建立異步循環代碼。
原文: Here are examples of everything new in ECMAScript 2016, 2017, and 2018
你的點贊是我持續分享好東西的動力,歡迎點贊!
乾貨系列文章彙總以下,以爲不錯點個Star,歡迎 加羣 互相學習。
https://github.com/qq44924588...
我是小智,公衆號「大遷世界」做者,對前端技術保持學習愛好者。我會常常分享本身所學所看的乾貨,在進階的路上,共勉!
關注公衆號,後臺回覆福利,便可看到福利,你懂的。