ECMAScript 2018(ES9)新特性
ECMAScript 2018(ES9)新特性:
- 异步迭代:
async 、await 。 - Promise方法::
finally() 。无论结果是 Resolved 或者是 Rejected 都会执行。 - Rest、Spread操作符和对象构建。
- 正则表达式:命名捕获组、反向断言、Unicode 属性转义。
- 模板文字和带标签的模板文字。
异步迭代:async、await
在异步/等待过程中的某个时刻,您将尝试在同步循环内调用异步函数。
async function process(array) {
for (let i of array) {
await doSomething(i);
}
}
// 它不会起作用
async function process(array) {
array.forEach(async i => {
await doSomething(i);
});
}
// 它不会起作用
循环本身保持同步,并且总是在它们的内部异步操作之前完成。ES2018 引入了异步迭代器,它与常规迭代器一样,只是方法返回一个 Promise。因此,关键字可以与循环一起使用以串行运行异步操作。
async function process(array) { forawait (let i of array) { doSomething(i); } }
Promise.finally()
在之前的 Promise 的调用链要么调用成功返回.then()方法,要么调用失败返回.catch()方法。在某些情况下,你想要在无论是成功还是失败,都运行同样的代码。例如实现清除、删除对话、关闭数据连接等操作。Promise.finally()允许你指定最终的逻辑。这为指定执行完 Promise 后,无论结果是 Resolved 或者是 Rejected 都需要执行的代码提供了一种方式。
Promise.finally()法接受一个回调函数作为参数,由于无法知道 Promise 实例的最终状态,所以finally()的回调函数中不接收任何参数,它仅用于无论最终结果如何都要执行的情况。
server.listen(0)
.then(function (){})
.catch(function (){})
.finally (server.stop);
function doSomething() {
doSomething1()
.then(doSomething2)
.then(doSomething3)
.catch(err => {
console.log(err);
})
.finally (() => {
// finish here!
});
}
Rest/Spread操作符和对象构建
Rest和Spread的操作符都是...,只不过使用的场景和目的不一样。Rest(展开)主要用在对象的解构,目前只支持对象的解构和不确定的参数描述。Spread(扩展)主要用在字面量对象的构建上。
数组
ES2015 为数组引入了 Rest(展开)参数和 Spread(扩展)运算符。
restParam(1, 2, 3, 4, 5);
function restParam(p1, p2, ...p3) {
// p1 = 1
// p2 = 2
// p3 = [3, 4, 5]
}
Spread 运算符以相反的方式工作,并将数组转换为可以传递给函数的单独参数。例如,给定任意数量的参数,返回最高值:Math.max()
const values = [99, 100, -1, 48, 16]; console.log( Math.max(...values) ); // 100
对象
ES2018 为对象解构提供了和数组一样的 Rest(展开)参数和 Spread(扩展)运算符。
const myObject = {
a: 1,
b: 2,
c: 3
};
const { a, ...x } = myObject;
// a = 1
// x = { b: 2, c: 3 }
或者您可以使用它将值传递给函数。
restParam({
a: 1,
b: 2,
c: 3
});
function restParam({ a, ...x }) {
// a = 1
// x = { b: 2, c: 3 }
}
跟数组一样,Rest参数只能在声明的结尾处使用。此外,它只适用于每个对象的顶层,如果对象中潜逃对象则无法适用。扩展运算符可以在其他对象内使用。
const obj1 = { a: 1, b: 2, c: 3 };
const obj2 = { ...obj1, z: 26 };
// obj2 is { a: 1, b: 2, c: 3, z: 26 }
您可以使用 Spread 运算符来克隆对象,但请注意,您只能获得浅拷贝。如果属性包含另一个对象,则克隆将引用同一对象。obj2 ={...obj1};
正则表达式
命名捕获组
JavaScript 正则表达式可以返回匹配对象-类似于数组的值,包含匹配的字符串。例如,要以 YYYY-MM-DD 格式解析日期:
const
reDate = /([0-9]{4})-([0-9]{2})-([0-9]{2})/,
match = reDate.exec('2018-04-30'),
year = match[1], // 2018
month = match[2], // 04
day = match[3]; // 30
它很难阅读,并且更改正则表达式也可能会更改匹配对象索引。
ES2018 允许在开始捕获括号后立即使用符号命名组。例如:?
const
reDate = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/,
match = reDate.exec('2018-04-30'),
year = match.groups.year, // 2018
month = match.groups.month, // 04
day = match.groups.day; // 30
任何未匹配的命名组都将其属性设置为 undefined。
命名捕获也可用于方法中。例如,将日期转换为美国 MM-DD-YYYY 格式:replace()
const
reDate = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/,
d = '2018-04-30',
usDate = d.replace(reDate, '$<month>-$<day>-$<year>');
反向断言
JavaScript 目前支持正则表达式中的前瞻断言。这意味着必须进行匹配但不捕获任何内容,并且断言不包含在整个匹配的字符串中。例如,要从任何价格中捕获货币符号:
const
reLookahead = /\D(?=\d+)/,
match = reLookahead.exec('$123.89');
console.log( match[0] ); // $
ES2018 引入以相同方式工作但是匹配前面的反向断言。这样我就可以忽略货币符号,单纯的捕获价格的数字:
const
reLookbehind = /(?<=\D)\d+/, match = reLookbehind.exec('$123.89'); console.log( match[0] ); // 123.89
以上是肯定反向断言,非数字\D必须存在。同样的,还存在否定反向断言,表示一个值必须不存在。例如:
const reLookbehindNeg = /(?// null<、small>
dotAll 模式
正则表达式中.(点)匹配除回车外的任何单字符,标记s改变这种行为,允许行终止符的出现,例如:
/hello.world/s.test('hello\nworld'); // true
Unicode 属性转义
到目前为止,还无法在正则表达式中本机访问 Unicode 字符属性。ES2018 在设置了u(Unicode)标志的正则表达式中,以\p{…}和\p{…}的形式,添加 Unicode 属性转义。
const reGreekSymbol = /\p{Script=Greek}/u;
reGreekSymbol.test('π'); // true
模板文字调整
之前,\u开始一个 unicode 转义,\x开始一个十六进制转义,\后跟一个数字开始一个八进制转义。这使得创建特定的字符串变得不可能,例如 Windows文件路径C:\uuu\xxx\111
ES2018 删除了与模板文字中的转义序列相关的所有语法限制。
