本篇文章介绍ECMAScript 2018(ES9)的新特性,来看看怎么使用它们。
async/await 异步迭代
ES8为我们带来 async/await
,使我们能在同步的写法中执行异步函数,但是在循环中:
async function foo(array) {
for (let i of array) {
await doSomething(i);
}
}
上面代码执行不符合预期,循环本身依旧保持同步,并在在内部异步函数之前全部调用完成。
ES2018引入异步迭代器(asynchronous iterators),使得 await
可以和 for...of
循环一起使用,以串行的方式运行异步操作。
async function foo(array) {
for await (let i of array) {
doSomething(i);
}
}
Promise.finally()
ES6为我们带来了 Promise
,但是它的结果要么成功 then
要么失败 catch
,使得我们的一些逻辑,如执行状态修改,结束回调都得在两边写一遍。
选择有了 finally()
,逻辑只可以放在一个地方了,这有点像以前 jQuery ajax
的 complete
。
return new Promise((reslove, reject) => {
// ...
}).then((res) => {
// reslove
}).catch((err) => {
// reject
}).finally(() => {
// complete
});
finally()
没有参数传入。
Rest/Spread 属性
ES2015引入了Rest参数和扩展运算符。当时三个点 ...
仅用于数组。
Rest
参数语法允许我们将一个剩余参数表示为一个数组。
function foo(a, b, ...rest) {
// a = 1
// b = 2
// rest = [3, 4, 5]
}
foo(1, 2, 3, 4, 5);
展开操作符则是将数组转换成可传递给函数的单独参数。
const nums = [1, 2, 3, 4, 5];
Math.max(...nums)); // 5
现在对象也可以使用它们了。
function foo({ a, b, ...rest }) {
// a = 1
// b = 2
// rest = { c: 3, d: 4, e: 5
}
foo({
a: 1,
b: 2,
c: 3,
d: 4,
e: 5
});
const object = {
a: 1,
b: 2,
c: 3,
d: 4,
e: 5
};
const { a, ...rest } = object;
// a = 1
// b = 2
// rest = { c: 3, d: 4, e: 5 }
跟数组一样,Rest参数只能在声明的结尾处使用。
正则表达式 s(dotAll模式)标记
在正则中,.
可以匹配任意字符,除了换行符。
/hello.es9/.test('hello\nes9'); // false
ES2018引入了dotAll模式,通过使用标记s
选项,.
就可以匹配换行符。
/hello.es9/s.test('hello\nes9'); // true
正则表达式 Unicode 转义
目前在正则中,可以通过字符集的名称来匹配字符。如s
代表空白
/^\s+$/u.test(' '); // true
在ES2018添加了Unicode属性转义,形式为\p{...}
和\P{...}
,在正则表达式中使用标记u
(unicode) 选项。
/^\p{White_Space}+$/u.test(' ') // true 空格
/^\p{Script=Greek}+$/u.test('μετά') // true 希腊字母
/^\p{Script=Latin}+$/u.test('Grüße') // true 匹配拉丁字母
/^\p{Surrogate}+$/u.test('\u{D83D}') // true 匹配单独的替代字符
lookbehind 反向断言
目前JavaScript在正则表达式中支持先行断言(lookahead)。这意味着匹配会发生,但是断言没有包含在整个匹配字段中。
如匹配字符串“10 hours”中紧跟着是”hours”的数字:
const reg = /\d+(?= hours)/u;
const matched = reg.exec('10 hours');
matched[0]; // 42
匹配字符串“10 minutes”中紧跟着不是”hours”的数字:
const reg = /\d+(?! hours)/u;
const matched = reg.exec('10 minutes');
matched[0]; // 42
ES2018引入以相同方式工作但是匹配前面的反向断言(lookbehind)。
匹配字符串“hours10”中”hours”后面的数字:
const reg = /(?<=hours)\d+/u;
const matched = reg.exec('hours10');
matched[0]; // 10
匹配字符串“minutes10”中数字前面不是“hours”:
const reg = /(?
Named capture groups 正则表达式命名捕获组
目前,正则表达式中小括号匹配的分组是通过索引编号的:
const reg = /(\d{4})-(\d{2})-(\d{2})/u;
const matched = reg.exec('2018-12-31');
matched[0]; // 2018-12-12
matched[1]; // 2018
matched[2]; // 12
matched[3]; // 31
代码可读性较差,并且改变正则表达式的结构有可能改变匹配对象的索引。
ES2018允许命名捕获组使用符号?
, 可以指定小括号中匹配内容的名称放在groups
里,这样可以提高代码的可读性。
const reg = /(?\d{4})-(?\d{2})-(?\d{2})/u;
const matched = reg.exec('2018-12-31');
matched.groups.year; // 2018
matched.groups.month; // 12
matched.groups.day; // 31
命名捕获组也可以使用在replace()
方法中。例如将日期转换为“年月日”格式:
const reg = /(?\d{4})-(?\d{2})-(?\d{2})/u;
'2018-12-31'.replace(reg, '$年$月$日'); // 2018年12月31日
非转义序列的模板字符串
ES2018 移除对 ECMAScript 在带标签的模版字符串中转义序列的语法限制。
之前,\u
开始一个 unicode 转义,\x
开始一个十六进制转义,\
后跟一个数字开始一个八进制转义。这使得创建特定的字符串变得不可能,例如Windows文件路径 C:\uuu\xxx\111
。
参考资料
- What’s New in ES2018
合集
- ES2021(ES12)新特性解读
- ES2020(ES11)带来的新特性
- ES2019(ES10)带来的9个新特性
- ES2018(ES9)新特性
- ES2017(ES8)新特性
- ES2016(ES7)新特性