ECMAScript 201六、2017和2018中全部新特性。

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

爲了保證的可讀性,本文采用意譯而非直譯。css

想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等着你!html

跟蹤JavaScript (ECMAScript)中的新內容是很困難的,並且更難找到有用的代碼示例。前端

所以,在本文中將介紹 TC39(最終草案) 在ES201六、ES2017和ES2018中添加的已完成提案中列出的全部18個特性,並給出有用的示例。git

圖片描述

1.Array.prototype.includes

include 是數組上的一個簡單實例方法,能夠輕鬆查找數組中是否有指定內容(包括 NaN)。github

圖片描述

2.求冪操做符

像加法和減法這樣的數學運算分別有像 + 和 - 這樣運算符。與它們相似,** 運算符一般用於指數運算。在ECMAScript 2016中,引入了 ** 代替 Math.pow。web

圖片描述



圖片描述

1.Object.values()

Object.values()是一個相似於Object.keys()的新函數,但返回對象自身屬性的全部值,不包括原型鏈中的任何值。正則表達式

圖片描述

2.Object.entries()

Object.entries()與Object.keys 相似,但它不是僅返回鍵,而是以數組方式返回鍵和值。 這使得在循環中使用對象或將對象轉換爲映射等操做變得很是簡單。數據庫

例一:segmentfault

圖片描述

例二:數組

圖片描述

3.字符串填充

在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=*=*=*=*='
當咱們想要在漂亮的打印顯示或終端打印進行對齊時,這很是有用。

3.1 padStart 例子:

在下面的例子中,有一個不一樣長度的數字列表。咱們但願在「0」爲追加符讓全部項長度都爲10位,以便顯示,咱們可使用padStart(10, '0')輕鬆實現這一點。

圖片描述

3.2 padEnd 例子:

當咱們打印多個不一樣長度的項目並想要右對齊它們時,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

3.3 ⚠️ 注意padStart和padEnd 在Emojis和其餘雙字節字符上的使用

Emojis和其餘雙字節字符使用多個unicode字節表示。因此padStart padEnd可能不會像預期的那樣工做!⚠️

例如:假設咱們要墊達到10個字符的字符串的心❤️emoji。結果以下:

'heart'.padStart(10, "❤️"); // prints.. '❤️❤️❤heart'

這是由於 ❤️ 長2個字節(' u2764 uFE0F')! 單詞 heart 是5個字符,因此咱們只剩下5個字符來填充。 因此 JS 使用 ('u2764uFE0F' ) 填充兩顆心並生成 ❤️❤️。 對於最後一個,它只使用 ('u2764uFE0F' ) 的第一個字節(u2764)來生成,因此是 ❤;

4.Object.getOwnPropertyDescriptors

此方法返回給定對象的全部屬性的全部屬性(包括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 !

5.函數參數的尾逗號

ES2017容許函數的最後一個參數有尾逗號(trailing comma), 此前,函數定義和調用時,都不容許最後一個參數後面出現逗號。這一變化將鼓勵開發人員中止醜陋的「行以逗號開頭」的習慣。這對於版本管理系統來講,就會顯示添加逗號的那一行也發生了變更。

圖片描述

6.Async/Await

到目前爲止,我的感覺是這是最重要和最有用的功能。 async 函數容許咱們不處理回調地獄,並使整個代碼看起來很簡單。

async 關鍵字告訴 JavaScript 編譯器以不一樣的方式對待函數。每當編譯器到達函數中的 await 關鍵字時,它就會暫停。它假定 wait 以後的表達式返回一個 promise ,並在進一步移動以前等待該 promise 被 resolved 或 rejected。

在下面的示例中,getAmount 函數調用兩個異步函數getUser和getBankBalance。使用 async await更加優雅和簡單達到有有序的調用 getUser 與 getBankBalance。

圖片描述

6.1.async 函數默認返回一個 promise

若是您正在等待 async 函數的結果,則須要使用 Promise 的 then 語法來捕獲其結果。

在如下示例中,咱們但願使用 console.log 來打印結果可是不在 doubleAndAdd 函數裏面操做。 由於 async 返回是一個 promise 對象,因此能夠在 then 裏面執行咱們一些打印操做。

圖片描述

6.2 並行調用 async/await

在前面的例子中,咱們調用doubleAfterlSec ,但每次咱們等待一秒鐘(總共2秒)。 相反,咱們可使用 Promise.all 將它並行化爲一個而且互不依賴於。

圖片描述

6.3 async/await 函數對錯誤的處理

在使用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);
  });
 }

圖片描述

7.共享內存 和 Atomics

這是一個巨大的、至關高級的特性,是JS引擎的核心加強。

其主要原理是在 JavaScript 中引入某種多線程特性,以便JS開發人員未來能夠經過容許本身管理內存而不是讓 JS 引擎管理內存來編寫高性能的併發程序。

這是經過一種名爲 SharedArrayBuffer (即 共享數組緩衝區) 的新類型的全局對象實現的,該對象本質上是將數據存儲在共享內存空間中。所以,這些數據能夠在主JS線程和web工做線程之間共享。

到目前爲止,若是咱們想在主 JS 線程和 web 工做者之間共享數據,咱們必須複製數據並使用postMessage 將其發送到另外一個線程。

你只需使用SharedArrayBuffer,數據就能夠當即被主線程和多個web工做線程訪問。workers 之間的協調變得更簡單和更快(與 postMessage() 相比)。

可是在線程之間共享內存會致使競爭條件。爲了幫助避免競爭條件,引入了 「Atomics」 全局對象。 Atomics 提供了各類方法來在線程使用其數據時鎖定共享內存。 它還提供了安全地更新該共享內存中的搜索數據的方法。

若是你這對個感興趣,能夠閱讀如下文章:

8. Tagged Template literal restriction removed

首先,咱們須要知道的什麼是 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" }

9.用於正則表達式的「dotall」標誌

目前在正則表達式中,雖然點(「.」)應該匹配單個字符,但它不匹配像 n r f 等新行字符。

例如:

//Before
/first.second/.test('first\nsecond'); //false

這種加強使 點 運算符可以匹配任何單個字符。爲了確保它不會破壞任何東西,咱們須要在建立正則表達式時使用s標誌。

//ECMAScript 2018
/first.second/s.test('first\nsecond'); //true   Notice: /s 👈🏼

更多的方法,請看這裏

圖片描述

10.RegExp Named Group Captures

這種加強 RegExp特性借鑑於像Python、Java等其餘語言,所以稱爲「命名組」。這個特性容許編寫開發人員以(<name>…)格式爲 RegExp 中的組的不一樣部分提供名稱(標識符),使用能夠用這個名稱輕鬆地獲取他們須要的任何組。

10.1 Named group 的基礎用法

在下面的示例中,咱們使用 (?<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

10.2 在 regex 內使用 Named groups

使用\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

10.3 在 String.prototype.replace 中使用 named groups

在 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"

11.對象的 Rest 屬性

rest操做 …(三個點)容許挑練咱們須要的屬性。

11.1 經過 Rest 解構你須要的屬性

圖片描述

let { firstName, age, ...remaining } = {
  firstName: '王',
  lastName: '智藝',
  age: 27,
  height: '1.78',
  race: '黃'
}

firstName; // 王
age; // 27
remaining; // { lastName: "智藝", height: "1.78", race: "黃" }

12.對象的擴展屬性

擴展 和 解析 的 三個點是同樣的,可是不一樣的是你能夠用 擴展 去新建或者組合一個新對象。

擴展 是對齊賦值的右運算符, 而 解構 是左運算符。

圖片描述

const person = { fName: '小明', age: 20 };
const account = { name: '小智', amount: '$1000'};

const personAndAccount = { ...person, ...account };
personAndAccount; // {fName: "小明", age: 20, name: "小智", amount: "$1000"}

13.正則表達式反向(lookbehind)斷言

斷言(Assertion)是一個對當前匹配位置以前或以後的字符的測試, 它不會實際消耗任何字符,因此斷言也被稱爲「非消耗性匹配」或「非獲取匹配」。

正則表達式的斷言一共有 4 種形式:

  • (?=pattern) 零寬正向確定斷言(zero-width positive lookahead assertion)
  • (?!pattern) 零寬正向否認斷言(zero-width negative lookahead assertion)
  • (?<=pattern) 零寬反向確定斷言(zero-width positive lookbehind assertion)
  • (?<!pattern) 零寬反向否認斷言(zero-width negative lookbehind assertion)

你可使用組(?<=…) 去正向斷言,也能夠用 (?<!…) 去取反。

正向斷言: 咱們想確保 # 在 winning 以前。(就是#winning),想正則匹配返回 winning。下面是寫法:

圖片描述

反向斷言:匹配一個數字,有 € 字符而沒有 $ 字符在前面的數字。

圖片描述

更多內容能夠參考:S2018 新特徵之:正則表達式反向(lookbehind)斷言

14. RegExp Unicode Property Escapes

用正則去匹配 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 匹配全部的表情。

圖片描述

參考文獻:

  1. ECMAScript 2018 Proposal
  2. https://mathiasbynens.be/note...

15. Promise.prototype.finally()

finally() 是 Promise 新增的一個實例方法。意圖是容許在 resolve/reject 以後執行回調。finally 沒有返回值,始終會被執行。

讓咱們看看各類狀況。

圖片描述

圖片描述

圖片描述

圖片描述

16.異步迭代(Asynchronous Iteration)

這是一個極其好用的新特性。讓咱們可以很是容易的建立異步循環代碼。

圖片描述

原文: Here are examples of everything new in ECMAScript 2016, 2017, and 2018

你的點贊是我持續分享好東西的動力,歡迎點贊!

交流

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

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

我是小智,公衆號「大遷世界」做者,對前端技術保持學習愛好者。我會常常分享本身所學所看的乾貨,在進階的路上,共勉!

關注公衆號,後臺回覆福利,便可看到福利,你懂的。

clipboard.png

相關文章
相關標籤/搜索