1. 程式人生 > >ES7和ES8的瞭解

ES7和ES8的瞭解

es7新特性
Es7在ES6的基礎上添加了三項內容:

*求冪運算子 (**)
Array.prototype.includes()方法.
函式作用域中嚴格模式的變更

Array.prototype.includes( )

includes()的作用,是查詢一個值在不在數組裡,若在,則返回true,反之返回false

Array.prototype.includes()方法接收兩個引數:要搜尋的值和搜尋的開始索引。當第二個引數被傳入時,該方法會從索引處開始往後

搜尋(預設索引值為0)。若搜尋值在陣列中存在則返回true,否則返回false。

includes()方法有一點不同,兩個NaN被認為是相等的,即使在NaN === NaN結果是false的情況下。
這一點和indexOf()的行為不同,indexOf()嚴格使用===判斷
includes()還有一個怪異的點需要指出,在判斷 +0 與 -0 時,被認為是相同的。
在這一點上indexOf()與includes()的處理結果是一樣的,前者同樣會返回 +0 的索引值

es8新特性
非同步函式(async function)
由於javascript是單執行緒的
做法通常是通過回撥函式實現JavaScript的非同步程式設計
假如存在還有更多的請求操作就會出現多層巢狀程式碼就會亂成一團 這種情況就被稱之為回撥函式地獄
於是promise被提出了它將回調函式的巢狀改成了鏈式呼叫

promise的最大問題是程式碼冗餘 ,請求任務時一堆的then,也使原來的語義變得很不清楚此時我們可以引入另外一種非同步程式設計的機制:generator

Es8引入了async函式使得非同步操作變得更加方便
例項如下:

Async function asyncFunc(params){
    const result1 = await this.login()
    const result2 = await this.getInfo()
}

非同步函式存在以下四種使用形式:
函式宣告: async function foo() {}
函式表示式: const foo = async function() {}
物件的方式: let obj = { async foo() {} }
箭頭函式: const foo = async () => {}

處理單個非同步結果:

async function asyncFunc(){
    const result = await otherAsyncFunc();
    console.log(result)
}

順序處理多個非同步結果:

async function asyncFunc(){
        const result1 = await otherAsyncFunc1();
        console.log(result1);
        const result2 = await otherAsyncFunc2();
        console.log(result2);
}

並行處理多個非同步結果:

async function asyncFunc(){
    const [result1,result2] = await.Promise.all({
        otherAsyncFunc1(),
        otherAsyncFunc2()
    })
    console.log(result1,result2);
}

處理錯誤:

Async function asyncFunc(){
    try{
       Await otherAsyncFunc(); 
    }catch(err){
        console.log(err)
    }
}

Object.entries( )和Object.values( )
Object.entries( )
1.目標物件是物件時,則每一個鍵值對都將會編譯成一個具有兩個元素的陣列
2.目標物件是陣列時,則會將陣列的下標作為鍵值返回

Object.entries({ one:1,two:2})            //[[‘one’,1],[’two’,2]]

Object.entries([1,2])                    //[[‘0’,1],[‘1’,2]]

注意:鍵值對中,如果鍵的值是Symbol,編譯時將會被忽略。例如:
Object.entries({ [Symbol()]: 1, two: 2 }) //[['two', 2]]

Object.entries()返回的陣列的順序與for-in迴圈保持一致,即如果物件的key值是數字,則返回值會對key值進行排序,返回的是排序後的結果。例如:
Object.entries({ 3: 'a', 4: 'b', 1: 'c' }) //[['1', 'c'], ['3', 'a'], ['4', 'b']]

使用Object.entries(),我們還可以進行物件屬性的遍歷。例如

let obj = { one: 1, two: 2 };
for (let [k,v] of Object.entries(obj)) {
  console.log(`${JSON.stringify(k)}: ${JSON.stringify(v)}`);
}

//輸出結果如下:
'one': 1
'two': 2

Object.values()
它的工作原理跟Object.entries()很像,顧名思義,它只返回自己的鍵值對中屬性的值。它返回的陣列順序,也跟Object.entries()保持一致。

Object.values({ one: 1, two: 2 }) //[1, 2]
Object.values({ 3: 'a', 4: 'b', 1: 'c' }) //['c', 'a', 'b']

字串填充:padStart和padEnd
ES8提供了新的字串方法-padStart和padEnd。padStart函式通過填充字串的首部來保證字串達到固定的長度,反之,padEnd是填充字串的尾部來保證字串的長度的。該方法提供了兩個引數:字串目標長度和填充欄位,其中第二個引數可以不填,預設情況下使用空格填充。

'Vue'.padStart(10)           //'       Vue'
'React'.padStart(10)         //'     React'
'JavaScript'.padStart(10)    //'JavaScript'

可以看出,多個數據如果都採用同樣長度的padStart,相當於將呈現內容右對齊。
上面示例中我們只定義了第一個引數,那麼我們現在來看看第二個引數,我們可以指定字串來代替空字串。

'Vue'.padStart(10, '_*')           //'_*_*_*_Vue'
'React'.padStart(10, 'Hello')      //'HelloReact'
'JavaScript'.padStart(10, 'Hi')    //'JavaScript'
'JavaScript'.padStart(8, 'Hi')     //'JavaScript'

從上面結果來看,填充函式只有在字元長度小於目標長度時才有效,若字元長度已經等於或小於目標長度時,填充字元不會起作用,而且目標長度如果小於字串本身長度時,字串也不會做截斷處理,只會原樣輸出。
padEnd函式作用同padStart,只不過它是從字串尾部做填充。來看個小例子:

'Vue'.padEnd(10, '_*')           //'Vue_*_*_*_'
'React'.padEnd(10, 'Hello')      //'ReactHello'
'JavaScript'.padEnd(10, 'Hi')    //'JavaScript'
'JavaScript'.padEnd(8, 'Hi')     //'JavaScript'

Object.getOwnPropertyDescriptors()
顧名思義,該方法會返回目標物件中所有屬性的屬性描述符,該屬性必須是物件自己定義的,不能是從原型鏈繼承來的。先來看個它的基本用法:

let obj = {
  id: 1,
  name: 'test',
  get gender() {
    console.log('gender')
  },
  set grade(g) {
    console.log(g)
  }
}
Object.getOwnPropertyDescriptors(obj)

//輸出結果為:

{
  gender: {
    configurable: true,
    enumerable: true,
    get: f gender(),
    set: undefined
  },
  grade: {
    configurable: true,
    enumerable: true,
    get: undefined,
    set: f grade(g)
  },
  id: {
    configurable: true,
    enumerable: true,
    value: 1,
    writable: true
  },
  name: {
    configurable: true,
    enumerable: true,
    value: 'test',
    writable: true
  }
}

方法還提供了第二個引數,用來獲取指定屬性的屬性描述符。

let obj = {
  id: 1,
  name: 'test',
  get gender() {
    console.log('gender')
  },
  set grade(g) {
    console.log(g)
  }
}
Object.getOwnPropertyDescriptors(obj, 'id')

//輸出結果為:

{
  id: {
    configurable: true,
    enumerable: true,
    value: 1,
    writable: true
  }
}

由上述例子可知,該方法返回的描述符,會有兩種型別:資料描述符、存取器描述符。返回結果中包含的鍵可能的值有:configurable、enumerable、value、writable、get、set。
使用過Object.assign()的同學都知道,assign方法只能拷貝一個屬性的值,而不會拷貝它背後的複製方法和取值方法。Object.getOwnPropertyDescriptors()主要是為了解決Object.assign()無法正確拷貝get屬性和set屬性的問題。

let obj = {
  id: 1,
  name: 'test',
  get gender() {
    console.log('gender')
  }
}
Object.assign(obj)

//輸出結果為:

{
  gender: undefined
  id: 1,
  name: 'test'
}

此時,Object.getOwnPropertyDescriptors方法配合Object.defineProperties方法,就可以實現正確拷貝。

let obj = {
  id: 1,
  name: 'test',
  get gender() {
    console.log('gender')
  }
}
let obj1 = {}
Object.defineProperties(obj1, Object.getOwnPropertyDescriptors(obj))
Object.getOwnPropertyDescriptors(obj1)

//輸出結果為:

{
  gender: {
    configurable: true,
    enumerable: true,
    get: f gender(),
    set: undefined
  },
  id: {
    configurable: true,
    enumerable: true,
    value: 1,
    writable: true
  },
  name: {
    configurable: true,
    enumerable: true,
    value: 'test',
    writable: true
  }
}

上述程式碼演示了,我們如何來拷貝一個屬性值為賦值方法或者取值方法的物件。更多Object.getOwnPropertyDescriptors的使用細則,可參見阮一峰的部落格文章,連結奉上:http://es6.ruanyifeng.com/#docs/object#Object-getOwnPropertyDescriptors
共享記憶體和原子(Shared memory and atomics)
ES8引入了兩部分內容:新的建構函式SharedArrayBuffer、具有輔助函式的名稱空間物件Atomics。共享記憶體允許多個執行緒併發讀寫資料,而原子操作則能夠進行併發控制,確保多個存在競爭關係的執行緒順序執行。
共享記憶體和原子也稱為共享陣列緩衝區,它是更高階的併發抽象的基本構建塊。它允許在多個工作者和主執行緒之間共享SharedArrayBuffer物件的位元組(緩衝區是共享的,用以訪問位元組,將其包裝在型別化的陣列中)。這種共享有兩個好處:
可以更快地在web worker之間共享資料
web worker之間的協調變得更加簡單和快速
那麼,我們為什麼要引入共享記憶體和原子的概念呢?以及SharedArrayBuffer的競爭條件是什麼,Atomics又是如何解決這種競爭的?推薦下面的文章,文章講解很詳細,圖文並茂,帶你深入瞭解SharedArrayBuffer和Atomics。
記憶體管理碰撞課程:https://segmentfault.com/a/1190000009878588
圖解 ArrayBuffers 和 SharedArrayBuffers:https://segmentfault.com/a/1190000009878632
用 Atomics 避免 SharedArrayBuffers 競爭條件:https://segmentfault.com/a/1190000009878699
Atomics物件提供了許多靜態方法,配合SharedArrayBuffer物件一起使用,可以幫助我們去構建一個記憶體共享的多執行緒程式設計環境。Atomic操作安裝在Atomics模組上。與其他全域性物件不同,Atomics不是建構函式。您不能使用new操作符或Atomics作為函式呼叫該物件。所有的屬性和方法Atomics都是靜態的,這一點跟Math類似。下面連結貼出了Atomics提供的一些基本方法:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics
關於共享記憶體和原子的深入研究,也可以參考Axel Rauschmayer博士的《Exploring ES2016 and ES2017》一書中的內容。具體章節連結如下:
http://exploringjs.com/es2016-es2017/ch_shared-array-buffer.html
函式引數列表與呼叫中的尾部逗號
該特性允許我們在定義或者呼叫函式時新增尾部逗號而不報錯。

let foo = function (
  a,
  b,
  c,
) {
  console.log('a:', a)
  console.log('b:', b)
  console.log('c:', c)
}
foo(1, 3, 4, )

//輸出結果為:
a: 1
b: 3
c: 4

上面這種方式呼叫是沒有問題的。函式的這種尾逗號也是向陣列和字面量物件中尾逗號看齊,它適用於那種多行引數並且引數名很長的情況,開發過程中,如果忘記刪除尾部逗號也沒關係,ES8已經支援這種寫法。
這麼用有什麼好處呢?
首先,當我們調整結構時,不會因為最後一行程式碼的位置變動,而去新增或者刪除逗號。
其次,在版本管理上,不會出現因為一個逗號,而使本來只有一行的修改,變成兩行。例如下面:

(
'abc'
)

(
'abc',
'def'
)

在我們版本管理系統裡,它會監測到你有兩處更改,但是如果我們不必去關心逗號的存在,每一行都有逗號時,新加一行,也只會監測到一行的修改。
建議的ES9功能
回想一下,每個ECMAScript功能提案都經過了幾個階段:
階段4意味著功能將在下一個版本中(或之後的版本)。
階段3意味著功能仍然有機會被包含在下一個版本中。
第4階段和部分ECMAScript規範草案
以下功能目前在第4階段:
Template Literal Revision:模板文字修訂(蒂姆·迪士尼)
候選功能(第3階段)
以下功能目前在第3階段:
Function.prototype.toString 修訂版(Michael Ficarra)
global(Jordan Harband)
Rest/Spread Properties:Rest/Spread屬性(SebastianMarkbåge)
Asynchronous Iteration:非同步迭代(Domenic Denicola)
import() (Domenic Denicola)
RegExp Lookbehind Assertions:RegExp Lookbehind斷言(Daniel Ehrenberg)
RegExp Unicode Property Escapes:RegExp Unicode屬性轉義(Brian Terlson,Daniel Ehrenberg,Mathias Bynens)
RegExp named capture groups:RegExp命名捕獲組(Daniel Ehrenberg,Brian Terlson)
s (dotAll) flag for regular expressions:s(dotAll)標誌為正則表示式(Mathias Bynens,Brian Terlson)
Promise.prototype.finally() (Jordan Harband)
BigInt - 任意精度整數(Daniel Ehrenberg)
Class fields(Daniel Ehrenberg,Jeff Morrison)
Optional catch binding(Michael Ficarra)
ES6-ES8的學習網站
ES6:http://es6.ruanyifeng.com/
ES7:https://www.css88.com/archives/tag/es7
ES8:https://www.css88.com/archives/tag/es8
TC39提案--javascript發展委員會