1、 异步迭代器(asynchronous iterators)
es2017 新增了 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);
}
}
2、Promise.finally()
ES6 为我们带来了 Promise,但是它的结果要么成功 then 要么失败 catch,使得我们的一些逻辑,如执行状态修改,结束回调都得在两边写一遍。
选择有了 finally(),逻辑只可以放在一个地方了,这有点像以前 jQuery ajax 的 complete。
return new Promise((reslove, reject) => {
// ...
})
.then((res) => {
// reslove
})
.catch((err) => {
// reject
})
.finally(() => {
// complete
});
finally()没有参数传入。
3、Rest/Spread 属性
ES2015 引入了 Rest 参数和扩展运算符。当时三个点...仅用于数组。
Rest 参数语法允许我们将一个剩余参数表示为一个数组。
function foo(a, b, ...rest) {
console.log(a);
console.log(b);
console.log(rest);
}
foo(1, 2, 3, 4, 5);
// 1
// 2
// [3, 4, 5]
展开操作符则是将数组转换成可传递给函数的单独参数。
const nums = [1, 2, 3, 4, 5];
Math.max(...nums);
// 5
现在对象也可以使用它们了。
function foo({ a, b, ...rest }) {
console.log(a);
console.log(b);
console.log(rest);
}
var obj = { a: 1, b: 2, c: 3, d: 4, e: 5 };
foo(obj);
// 1
// 2
// { c: 3, d: 4, e: 5 }
var obj = { a: 1, b: 2, c: 3, d: 4, e: 5 };
const { a, b, ...rest } = obj;
console.log(a); // 1
console.log(b); // 2
console.log(rest); // { c: 3, d: 4, e: 5 }
跟数组一样,Rest 参数只能在声明的结尾处使用。
4、正则表达式 s(dotAll 模式)标记
在正则中,.可以匹配任意字符,除了换行符。
/hello.es9/.test("hello\nes9");
// false
ES2018 引入了 dotAll 模式,通过使用标记 s 选项,.就可以匹配换行符。
/hello.es9/s.test("hello\nes9");
// true
5、正则表达式 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
6、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 = /(?<!hours)\d+/u;
const matched = reg.exec("minutes10");
matched[0];
// 10
7、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 = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\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 = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
"2018-12-31".replace(reg, "$<year>年$<month>月$<day>日");
// 2018年12月31日
8、非转义序列的模板字符串
ES2018 移除对 ECMAScript 在带标签的模版字符串中转义序列的语法限制。
之前,\u 开始一个 unicode 转义,\x 开始一个十六进制转义,\后跟一个数字开始一个八进制转义。这使得创建特定的字符串变得不可能,例如 Windows 文件路径 C:\uuu\xxx\111。