ECMAScript是JavaScript的基礎標準,通常縮寫為ES。了解有關ECMAScript的所有內容,以及ES2017(也稱為ES8)中加入的功能。
ECMAScript 2017是ECMA-262標準的第8版(也常簡稱為ES2017或ES8),於2017年6月定案。
與ES6相比,ES8針對JavaScript來說是一個很小的更新,但它仍然引入了非常有用的功能:
- 字串填充
Object.values()
Object.entries()
Object.getOwnPropertyDescriptors()
- 函式參數列表和呼叫中的尾部逗號
- Async函式
- 共享內存和原子操作
字串填充
字串填充的目的是將字符添加到字串中,使其達到特定長度。
ES2017引入了兩個String
方法:padStart()
和padEnd()
。
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()
此方法返回包含所有對象自有屬性值的陣列。
用法:
const person = { name: 'Fred', age: 87 }
Object.values(person) // ['Fred', 87]
Object.values()
也可以用於陣列:
const people = ['Fred', 'Tony']
Object.values(people) // ['Fred', 'Tony']
Object.entries()
此方法返回包含所有對象自有屬性的陣列,作為包含[key,value]對的陣列。
用法:
const person = { name: 'Fred', age: 87 }
Object.entries(person) // [['name', 'Fred'], ['age', 87]]
Object.entries()
也可以用於陣列:
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()
將無法將其正確複製到新對象中。
例如,使用以下方式將不起作用:
const person1 = {
set name(newName) {
console.log(newName)
}
}
以下方式將起作用:
const person3 = {}
Object.defineProperties(person3,
Object.getOwnPropertyDescriptors(person1))
通過以下簡單的控制台測試可以看到:
person1.name = 'x'
"x"
person2.name = 'x'
person3.name = 'x'
"x"
person2
缺少setter,它未被複製。
對於使用Object.create()
進行淺克隆的對象也存在同樣的限制。
尾部逗號
此功能允許在函式聲明和函式呼叫中使用尾部逗號:
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函式。
快速示例
當使用非同步函式編寫代碼時,可以這樣寫:
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')
上面的代碼將在瀏覽器控制台中打印出以下內容:
Before
After
I did something //3秒後
連續使用多個Async函式
非同步函式非常容易進行鏈式調用,而且語法比普通Promises更易讀:
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以來,您可以使用SharedArrayBuffer
在Web Workers和創建它們的線程之間創建共享內存陣列。
由於不知道將寫入共享內存區域需要多少時間才能傳播,Atomics是一種確保讀取值時完成任何寫入操作的方法。
有關此內容的更多細節可以在規範提案中找到,並已經得到實現。