ES7 and ES8 特性

最近我寫了一篇博客文章,甚至做一篇關于ES6/ES2015在線課程。你猜怎么樣?TC39-JavaScript最強勢的監工-正在邁向ES8,所以讓我們來了解下ES7 and ES8(官方稱ES2016 and ES2017),幸運的是,他們比ES6標準功能少好多好多,真的,ES7只有2個新特性。

ES7 特性:
1.Array.prototype.includes
2.Exponentiation Operator(求冪運算)

Paste_Image.png

ES8在本文(2017年1月)之前尚未完成。但我們可以假設所有完成的提案(第4階段)和大多數階段3(更多的階段在這里和我的課程)2017年(ES8)完成的提案:
1.Object.values/Object.entries
2.String padding(字符串填充)
3.Object.getOwnPropertyDescriptors
4.函數參數列表和調用中的尾逗號(Trailing commas)
5.異步函數(Async Functions)

本文中我不會介紹stage 3的提案,但你可以在這里檢查階段1到3的建議的狀態。

讓我們深入了解建議和功能。

Array.prototype.includes

Array.prototype.includes用法都容易和簡單。它是一個替代indexOf,開發人員用來檢查數組中是否存在值,indexOf是一種尷尬的使用,因為它返回一個元素在數組中的位置或者-1當這樣的元素不能被找到的情況下。所以它返回一個數字,而不是一個布爾值。開發人員需要實施額外的檢查。在ES6,要檢查是否存在值你需要做一些如下圖所示小技巧,因為他們沒有匹配到值,Array.prototype.indexOf返回-1變成了true(轉換成true),但是當匹配的元素為0位置時候,該數組包含元素,卻變成了false

let arr = ['react', 'angular', 'vue']

// WRONG
if (arr.indexOf('react')) { // 0 -> evaluates to false, definitely as we expected
  console.log('Can use React') // this line would never be executed
}

// Correct
if (arr.indexOf('react') !== -1) {
  console.log('Can use React')
}

或者使用一點點hack 位運算符 ~ 使代碼更加緊湊一些,因為~(位異或)對任何數字相當于-(a + 1):

let arr = ['react', 'angular', 'vue']

// Correct
if (~arr.indexOf('react')) {
  console.log('Can use React')
}

在ES7中使用includes代碼如下:

let arr = ['react', 'angular', 'vue']

// Correct
if (arr.includes('react')) {
  console.log('Can use React')
}

開發者還能在字符串中使用includes:

let str = 'React Quickly'

// Correct
if (str.toLowerCase().includes('react')) {  // true
  console.log('Found "react"')  
}

有趣的是,許多JavaScript庫已經實現includes或類似功能contains
(但TC39決定不使用名稱contains因為MooTools):

  • jQuery: $.inArray
  • Underscore.js: _.contains
  • Lodash: _.includes (在版本3或者早期版本中是_.contains 和 Underscore一樣)
  • CoffeeScript: in 操作(example)
  • Darf: list.contains (example)
    除了增強了可讀性語義化,實際上給開發者返回布爾值,而不是匹配的位置。includes也可以在NaN(非數字)使用。最后 ,includes第二可選參數fromIndex,這對于優化是有好處的,因為它允許從特定位置開始尋找匹配。
    更多例子:
console.log([1, 2, 3].includes(2)) // === true)
console.log([1, 2, 3].includes(4)) // === false)
console.log([1, 2, NaN].includes(NaN)) // === true)
console.log([1, 2, -0].includes(+0)) // === true)
console.log([1, 2, +0].includes(-0)) // === true)
console.log(['a', 'b', 'c'].includes('a')) // === true)
console.log(['a', 'b', 'c'].includes('a', 1)) // === false)

總而言之,includes在一個數組或者列表中檢查是否存在一個值,給任何開發人員帶來簡單性。

Exponentiation Operator(求冪運算)

求冪運算大多數是為開發者做一些數學計算,對于3D,VR,SVG還有數據可視化非常有用。在ES6或者早些版本,你不得不創建一個循環,創建一個遞歸函數或者使用Math.pow,如果你忘記了什么是指數,當你有相同數字(基數)自相相乘多次(指數)。例如,7的3次方是7*7*7

所以在ES6/2015ES,你能使用Math.pow創建一個短的遞歸箭頭函數

calculateExponent = (base, exponent) => base*((--exponent>1)?calculateExponent(base, exponent):base)
console.log(calculateExponent(7,12) === Math.pow(7,12)) // true
console.log(calculateExponent(2,7) === Math.pow(2,7)) // true

現在在ES7 /ES2016,以數學向導的開發者可以使用更短的語法:

let a = 7 ** 12
let b = 2 ** 7
console.log(a === Math.pow(7,12)) // true
console.log(b === Math.pow(2,7)) // true

開發者還可以操作結果:

let a = 7
a **= 12
let b = 2
b **= 7
console.log(a === Math.pow(7,12)) // true
console.log(b === Math.pow(2,7)) // true

許多ES新特性是從其他語言(CoffeeScript-俺最愛,Ruby等)模仿而來的。你可以猜到,指數運算符在其他語言的存在形式:

  • Python: x ** y
  • CoffeeScript: x ** y
  • F#: x ** y
  • Ruby: x ** y
  • Perl: x ** y
  • Lua, Basic, MATLAB: x ^ y
    對我個人而言沒有指數運算不是什么問題。除了這次,在我15年的Javascript訪談和代碼教程寫作中沒有寫過指數運算。指數運算符是你們最需要的特性么?

Object.values/Object.entries

Object.valuesObject.entries是在ES2017規格中,它和Object.keys類似,返回數組類型,其序號和Object.keys序號對應。

Object.values,Object.entriesObject.keys各自項返回是數組,相對應包括key,value或者可枚舉特定對象property/attribute

在ES8 /ES2017之前,Javascript開發者需要迭代一個對象的自身屬性時候不得不用Object.keys,通過迭代且使用obj[key]獲取value值返回一個數組:

let obj = {a: 1, b: 2, c: 3}
Object.keys(obj).forEach((key, index)=>{
  console.log(key, obj[key])
})

而使用ES6/ES2015 中for/of稍微好點:

let obj = {a: 1, b: 2, c: 3}
for (let key of Object.keys(obj)) {
  console.log(key, obj[key])
}

你使用老方式for/in(ES5)也許用的非常好。但是他會迭代所有可以枚舉屬性(像原型中的帶名字的-see MDN),不僅僅自己的屬性,會意外的破壞那些 像prototypetostring得到意想不到的值。
Object.values返回對象自身可以迭代屬性值(values)為數組類型。我們最好使用Array.prototype.forEach迭代它,結合ES6的箭頭函數隱形返回值:

let obj = {a: 1, b: 2, c: 3}
Object.values(obj).forEach(value=>console.log(value)) // 1, 2, 3

或者使用for/of:

let obj = {a: 1, b: 2, c: 3}
for (let value of Object.values(obj)) {
  console.log(value)
}
// 1, 2, 3

·Object.entries·,在另一方面,將會返回對象自身可迭代屬性key-value對數組(作為一個數組),他們(key-value)分別以數組存放數組中。

let obj = {a: 1, b: 2, c: 3}
JSON.stringify(Object.entries(obj))
"[["a",1],["b",2],["c",3]]"

我們可以使用ES6/ES2015解構(需要深入了解解構請點擊這篇文章課程),從這嵌套數組中分別聲明key和value

let obj = {a: 1, b: 2, c: 3}
Object.entries(obj).forEach(([key, value]) => {
 console.log(`${key} is ${value}`)
})
// a is 1, b is 2, c is 3

你可以猜一猜,我們同樣使用ES6for/of(畢竟全部都是數組)遍歷Object.entries返回來的結果值。

let obj = {a: 1, b: 2, c: 3}
for (let [key, value] of Object.entries(obj)) {
  console.log(`${key} is ${value}`)
}
// a is 1, b is 2, c is 3

現在從對象中提取values和key-value pairs 變得非常容易了。Object.valuesObject.entries這種方式不想之前 Object.keys(自身屬性key+順序相同)結合for/of(ES6)一起,我們不僅僅可以提取他們還可以迭代他們。

字符填充函數padStart 和 padEnd

String.prototype.padStartString.prototype.padEnd在javascript字符操作是一個不錯的體驗,幫助避免依賴而外的庫。
padStart()在開始部位填充,返回一個給出長度的字符串,填充物給定字符串,把字符串填充到期望的長度。從字符串的左邊開始(至少大部分西方語言),一個經典例子是使用空格創建列:

console.log('react'.padStart(10).length)         // "       react" is 10
console.log('backbone'.padStart(10).length)         // "  backbone" is 10

它對于財務方面非常有用:

console.log('0.00'.padStart(20))            
console.log('10,000.00'.padStart(20))    
console.log('250,000.00'.padStart(20))    

這結果作為一個會計總賬格式非常漂亮:

                0.00
           10,000.00
          250,000.00

第二個參數,讓我們放一些其他的填充字符替代空字符串,一個字符串填充:

console.log('react'.padStart(10, '_'))         // "_____react"
console.log('backbone'.padStart(10, '*'))         // "**backbone"

padEnd顧名思義就是從字符串的尾端右邊開始填充。第二個參數,你能實際上用一個任何長度的字符串。例如:

console.log('react'.padEnd(10, ':-)'))         // "react:-):-" is 10
console.log('backbone'.padEnd(10, '*'))         // "backbone**" is 10

Object.getOwnPropertyDescriptors

這新的 Object.getOwnPropertyDescriptors返回對象obj所有自身屬性描述。這是一個多參數版本的Object.getOwnPropertyDescriptors(obj,propName)將會返回obj中propName屬性的一個單獨描述。
在我們日常不可變編程(immutable programming)時代中,有了這個方法很方便(記住,Javascript中對象是引用傳遞)在ES5中,開發者要使用Object.assign()來拷貝對象, Object.assign()分配屬性只有copy和定義新的屬性。當我們使用更加復雜對象和類原型,這可能會出問題。
Object.getOwnPropertyDescriptors允許創建真實的對象淺副本并創建子類,它通過給開發者描述符來做到這一點.在Object.create(prototype, object)放入描述符后,返回一個真正的淺拷貝

Object.create(
  Object.getPrototypeOf(obj),
  Object.getOwnPropertyDescriptors(obj)
)

或者你可以合并兩個對象targetsource如下:

Object.defineProperties(
  target,
  Object.getOwnPropertyDescriptors(source)
)

以上是Object.getOwnPropertyDesciptors用法。但是什么是描述符(descriptor)呢?就是一個對象的描述,廢話!
好吧!好吧!,讓我們挖掘一下描述符一點點多信息。這里有兩種描述符號類型:
1.數據描述符(Data descriptor)
2.存取器描述符(Accessor descriptor)
存取描述符有必須屬性:get 或者set或者get和set兩個就是如你所想的getter和setter函數,然后存取描述符還有可選屬性configurableenumerable

let azatsBooks = {  
  books: ['React Quickly'],
  get latest () {
    let numberOfBooks = this.books.length
    if (numberOfBooks == 0) return undefined
    return this.books[numberOfBooks - 1]
  }
}

這個例子數據描述符booksObject.getOwnPropertyDescriptor(azatsBooks, 'books')產生結果如下:

Object
    configurable: true
    enumerable: true
    value: Array[1]
    writable: true
    __proto__: Object

同樣的,Object.getOwnPropertyDescriptor(azatsBooks, 'latest')將會展現latest的描述符,這個latest(get)存取器描述符展現如下:

Object
    configurable: truee
    numerable: true
    get: latest()
    set: undefined
    __proto__: Object

現在我們調用新方法獲取所有的描述符:

console.log(Object.getOwnPropertyDescriptors(azatsBooks))

它會給出這個對象兩個描述符books和latest:

Object
  books: Object
    configurable: true
    enumerable: true
    value: Array[1]
    writable: true
    __proto__: Object
  latest: Object
    configurable: true
    enumerable: true
    get: latest()
    set: undefined
    __proto__: Object
  __proto__: Object

或者你可以使用Devtools格式化一下,下面截圖:

Paste_Image.png

函數參數列表和調用中的尾逗號

尾逗號在函數定義中只是一個純粹語法變化,在ES5中,將會非法語法,在函數參數后面應該是沒有逗號的:

var f = function(a,
  b,
  c,
  d) { // NO COMMA!
  // ...
  console.log(d)
}
f(1,2,3,'this')

在ES8中,這種尾逗號是沒有問題的:

var f = function(a,
  b,
  c,
  d,
) { // COMMA? OK!
  // ...
  console.log(d)
}
f(1,2,3,'this')

現在,函數中尾逗號是向數組(ES3)中和字面量對象(ES5)中尾逗號看齊。

var arr = [1,  // Length == 3
  2,
  3,
]  // <--- ok
let obj = {a: 1,  // Only 3 properties
  b: 2,
  c: 3,
}  // <--- ok

更不用說他是無用友好的。

尾逗號主要有用在使用多行參數風格(典型的是那些很長的參數名),開發者終于可以忘記逗號放在第一位這種奇怪的寫法。自從逗號bugs主要原因就是使用他們。而現在你可以到處使用逗號,甚至最后參數都可以。

異步函數

異步函數(或者async/await)特性操作是Promise最重要的功能。所以你大概進一步閱讀他們或者看一個進修視頻課程來。這種想法是為了在寫異步代碼中簡化它,因為人類大腦最討厭這種平行非序號思維了。它只是不會演變這種方式。
對于我個人來說,我不喜歡Promise,就僅僅相比callback顯得特別冗余。所以我從來沒有使用過它,幸運的是,在ES8,異步函數是那么給力。開發者定義一個asyc函數里面不包含或者包含await 基于Promise異步操作。在這引擎之下一個異步函數返回一個Promise,無論無何你在任何地方不會看到這樣的一個詞(注:Promise)(當然了,你非的自己使用)。
例如,在ES6中我們可以使用Promise,Axios庫向GraphQL服務器發送一個請求:

axios.get(`/q?query=${query}`)
  .then(response => response.data)
  .then(data => {
    this.props.processfetchedData(data) // Defined somewhere else
  })
  .catch(error => console.log(error))

任何一個Promise庫都能兼容新的異步函數,我們可以使用同步try/catch做錯誤處理。

async fetchData(url) => {
  try {
    const response = await axios.get(`/q?query=${query}`)
    const data = response.data
    this.props.processfetchedData(data)
  } catch (error) {
    console.log(error)
  }
}

異步函數返回一個Promise,所以我們像下面可以繼續執行流程:

async fetchData(query) => {
  try {
    const response = await axios.get(`/q?query=${query}`)
    const data = response.data
    return data
  } catch (error) {
    console.log(error)
  }
}
fetchData(query).then(data => {
  this.props.processfetchedData(data)
})

你可以看到這段代碼在(Babel REPL)生效。請注意,這個例子中,Axios庫被代替的,是通過模擬來做相同功能,而HTTP請求通過setTimout代替:

let axios = {  // mocks
  get: function(x) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve({data: x})
    }, 2000)
  })
}}
let query = 'mangos'
async function fetchData(query) {
  try {
    const response = await axios.get(`/q?query=${query}`)
    const data = response.data
    return data
  } catch (error) {
    console.log(error)
  }
}
fetchData(query).then(data => {
  console.log(data) // Got data 2s later... Can use data!
})

有了 async/await,我們的代碼執行異步看起來像執行同步一樣。可以從頭到尾讀起來非常簡單和易懂,因為出現結果順序和函數題中從頭到尾順序一樣啊!

小結

這就是或多或少ES8特性(還沒有定稿),和已經定稿的ES7(已經定稿),如果你使用Babel,Traceur或者類似編譯器,您可以使用這些所有功能以及更多0~3 stage功能,而不需要等瀏覽器實現他們。ES7和ES8將簡單轉換ES5兼容代碼,即使是IE9都可以運行:)
一些ES8功能需要注意了,因為他們還是處于stage3階段,但是有可能出現ES8/ES2017中。

  • 共享內存和原子(Shared Memory and Atomics)
  • SIMD.JS - SIMD APIs
  • Function.prototype.toString
  • 提升模板文字限制(Lifting Template Literal Restriction)
  • global
  • Rest/Spread Properties
  • 異步迭代(Asynchronous Iteration)
  • import()
    你可以時刻關注他們的狀態 進行中提案已經完成的提案
    PS:需要復習 Primose、箭頭函數、let/const和其他ES6/ES2015功能,請閱讀我的博客和視頻。
    PS2:如果你更喜歡觀看視頻的話,請登錄Node.University’sES6/ES2015 course,還有即將來臨的ES7和ES8視頻課程

原文地址:https://node.university/blog/498412/es7-es8?utm_source=javascriptweekly&utm_medium=email 【愛在西元前翻譯】

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,362評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,577評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,486評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,852評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,600評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,944評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,944評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,108評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,652評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,385評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,616評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,111評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,798評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,205評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,537評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,334評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,570評論 2 379

推薦閱讀更多精彩內容

  • 最近我寫了一篇博客文章,甚至做一篇關于ES6/ES2015在線課程。你猜怎么樣?TC39-JavaScript最強...
    sunnyRube閱讀 1,704評論 1 2
  • 期待已久的新課上線啦!解鎖React Native開發新姿勢,一網打盡React Native最新與最熱技術,點我...
    CrazyCodeBoy閱讀 5,080評論 3 31
  • ES2016特性: Array.prototype.includes(數組元素判斷) includes 方法與 i...
    hlemon閱讀 5,483評論 0 1
  • 歌詞:嫁到鄂爾多斯來 遠心 你是我的斡爾朵 在你的大帳里跳舞唱歌 吸引世界的璀璨星河 你是我的鄂爾多斯 一首純正的...
    遠心篤行閱讀 661評論 0 2
  • 很難去完整描述心底的想法。 這個結果我并不意外,我感到出乎意料的是,當事人真正面對這個結果時的反應,有點驚訝,有合...
    回聲與兔人閱讀 214評論 0 0