/

ES2017指南

ES2017指南

ECMAScript是JavaScript的基礎標準,通常縮寫為ES。了解有關ECMAScript的所有內容,以及ES2017(也稱為ES8)中加入的功能。

ECMAScript 2017是ECMA-262標準的第8版(也常簡稱為ES2017ES8),於2017年6月定案。

與ES6相比,ES8針對JavaScript來說是一個很小的更新,但它仍然引入了非常有用的功能:

字串填充

字串填充的目的是將字符添加到字串中,使其達到特定長度。

ES2017引入了兩個String方法:padStart()padEnd()

1
2
padStart(targetLength [, padString])
padEnd(targetLength [, padString])

範例用法:

padStart()
‘test’.padStart(4) ‘test’
‘test’.padStart(5) ’ test’
‘test’.padStart(8) ’    test’
‘test’.padStart(8, ‘abcd’) ‘abcdtest’
padEnd()
‘test’.padEnd(4) ‘test’
‘test’.padEnd(5) ‘test ’
‘test’.padEnd(8) ‘test    ’
‘test’.padEnd(8, ‘abcd’) ‘testabcd’

Object.values()

此方法返回包含所有對象自有屬性值的陣列。

用法:

1
2
const person = { name: 'Fred', age: 87 }
Object.values(person) // ['Fred', 87]

Object.values()也可以用於陣列:

1
2
const people = ['Fred', 'Tony']
Object.values(people) // ['Fred', 'Tony']

Object.entries()

此方法返回包含所有對象自有屬性的陣列,作為包含[key,value]對的陣列。

用法:

1
2
const person = { name: 'Fred', age: 87 }
Object.entries(person) // [['name', 'Fred'], ['age', 87]]

Object.entries()也可以用於陣列:

1
2
const people = ['Fred', 'Tony']
Object.entries(people) // [['0', 'Fred'], ['1', 'Tony']]

getOwnPropertyDescriptors()

該方法返回對象的所有自有(非繼承的)屬性描述符。

JavaScript中的任何對象都有一組屬性,每個屬性都有一個描述符。

描述符是屬性的一組屬性,由以下子集組成:

  • value:屬性的值
  • writable:如果為true,屬性可以更改
  • get:屬性的getter函式,在讀取屬性時調用
  • set:屬性的setter函式,在將屬性設置為某個值時調用
  • configurable:如果為false,則該屬性無法刪除,也無法更改任何屬性,除了其值
  • enumerable:如果該屬性是可枚舉的,則為true

Object.getOwnPropertyDescriptors(obj)接受一個對象,並返回一個具有描述符集的對象。

這有什麼用處?

ES6提供了Object.assign(),它會從一個或多個對象中複製所有可枚舉的自有屬性,並返回一個新對象。

但是這其中存在一個問題,它無法正確複製具有非默認屬性的屬性。

例如,如果一個對象只有一個setter,使用Object.assign()將無法將其正確複製到新對象中。

例如,使用以下方式將不起作用:

1
2
3
4
5
const person1 = {
set name(newName) {
console.log(newName)
}
}

以下方式將起作用:

1
2
3
const person3 = {}
Object.defineProperties(person3,
Object.getOwnPropertyDescriptors(person1))

通過以下簡單的控制台測試可以看到:

1
2
3
4
5
6
7
person1.name = 'x'
"x"

person2.name = 'x'

person3.name = 'x'
"x"

person2缺少setter,它未被複製。

對於使用Object.create()進行淺克隆的對象也存在同樣的限制。

尾部逗號

此功能允許在函式聲明和函式呼叫中使用尾部逗號:

1
2
3
4
5
const doSomething = (var1, var2,) => {
//...
}

doSomething('test2', 'test2',)

這種更改將促使開發人員停止使用“在行首使用逗號”的不好習慣。

Async函式

請查看有關async/await的專題文章

ES2017引入了async函式的概念,這是此ECMAScript版本中引入的最重要的更改。

Async函式是在Promises和generators之上結合起來的,用於減少Promises周圍的冗餘代碼以及Promises鏈式調用的“不要中斷鏈式調用”的限制。

它們的好處

它是對Promises的高級抽象。

當Promises在ES6中引入時,它們的目的是解決與異步代碼相關的問題,它們確實解決了這個問題,但在ES6和ES2017之間的2年時間內,很明顯Promises不能成為最終解決方案。Promises的出現是為了解決著名的“回調地獄”問題,但它們本身引入了復雜性和語法復雜性。它們只是好的基本元素,有了更好的語法,開發人員可以更好地使用它們:這就是async函式

快速示例

當使用非同步函式編寫代碼時,可以這樣寫:

1
2
3
4
5
6
7
8
9
10
11
12
13
function doSomethingAsync() {
return new Promise((resolve) => {
setTimeout(() => resolve('I did something'), 3000)
})
}

async function doSomething() {
console.log(await doSomethingAsync())
}

console.log('Before')
doSomething()
console.log('After')

上面的代碼將在瀏覽器控制台中打印出以下內容:

1
2
3
Before
After
I did something //3秒後

連續使用多個Async函式

非同步函式非常容易進行鏈式調用,而且語法比普通Promises更易讀:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function promiseToDoSomething() {
return new Promise((resolve)=>{
setTimeout(() => resolve('I did something'), 10000)
})
}

async function watchOverSomeoneDoingSomething() {
const something = await promiseToDoSomething()
return something + ' and I watched'
}

async function watchOverSomeoneWatchingSomeoneDoingSomething() {
const something = await watchOverSomeoneDoingSomething()
return something + ' and I watched as well'
}

watchOverSomeoneWatchingSomeoneDoingSomething().then((res) => {
console.log(res)
})

共享內存和原子操作

Web Workers用於在瀏覽器中創建多線程程序。

它們通過事件提供消息協議。自從ES2017以來,您可以使用SharedArrayBufferWeb Workers和創建它們的線程之間創建共享內存陣列。

由於不知道將寫入共享內存區域需要多少時間才能傳播,Atomics是一種確保讀取值時完成任何寫入操作的方法。

有關此內容的更多細節可以在規範提案中找到,並已經得到實現。

tags: [“JavaScript”, “ES2017”, “ES8”, “String padding”, “Object.values()”, “Object.entries()”, “getOwnPropertyDescriptors()”, “Trailing commas”, “Async functions”, “Shared Memory and Atomics”]