ES2018(ES9)的新功能
in Master Pageviews
在本文中,我将介绍通过ES2018(ES9)引入的JavaScript的新功能,以及它们的用途及如何使用它们。
Javascript(ECMAScript)是一个不断发展的标准,由多个平台上的许多供应商共同实现,ES6(ECMAScript 2015)是一个大型的版本,花了足足六年的时间才完成。ES9(ECMAScript 2018)是目前最新的版本。
技术委员会39(TC39)由包括浏览器供应商在内的各方组成,他们推进Javascript提案沿着一条严格的发展道路前进;
- 第零阶段:strawman-最初想法的提交
- 第一阶段:proposal(提案)-由TC39一名正式成员倡导的正是提案文件,该文件包括API示例
- 第二阶段:draft(草案)-功能规范的初始版本,包括两个实验性实例
- 第三阶段:candidate(候选)-提案规范通过审查并从厂商那里手机反馈信息
- 第四阶段:finished(完成)-提案已准备好包含在ECMAScript中,一个功能只有达到此阶段时才能被视为标准。但是,在浏览器和Node.js等运行中时可能还需要更长的时间。
ES2016
ES2016通过添加两个小功能证明了标准化过程:
ES2017
ES2017提供了更多的新功能:
- 异步函数可实现更清晰的
Promise
语法 Object.values()
返回一个给定对象自己的所有可枚举属性值的数组,值的顺序与使用for…in循环遍历的顺序相同(for...in
枚举原型链中的属性)Object.entries()
返回一个给定对象自身可枚举属性的键值对数组,其排列与使用for...in
循环遍历对象是返回的顺序一致(for...in
枚举原型链中的属性)Object.getOwnPropertyDescriptors
返回一个对象所有自身属性的描述符(.value, .writable, .get, .set, .configurable, .enumerable)padStart()
和padEnd()
都可以填充字符串长度- 结尾
,
(逗号),数组定义和函数参数列表 ShareArrayBuffer
和Atomics
用于从共享内存位置读取和写入
关于更多ES2017的信息请参考What’s new in ES2017
ES2018
ECMAScript 2018 (ES9)现在已经推出,以下功能已经达到第四个阶段,但各个浏览器的运行情况稍有差别。
异步迭代
在async/await的某些时刻,你可以尝试在同步循环中调用异步函数。如:
async function process(array) {
for(let i of array) {
await doSomething(i);
}
}
它不会起作用,下面代码也不会:
async function(array) {
array.forEach(async i => {
await doSomething(i);
});
}
循环本身保持同步,并且总是在它们的内部异步操作之前完成。
ES2018引入了异步迭代器(asyncchronous iterators),它与常规迭代器一样,只是返回一个Promise。因此,await关键字可以和for…in循环一起使用,以串行方式运行异步操作。例如:
async function process(array) {
for await(let i in array) {
doSomething(i);
}
}
Promise.finally()
Promise链要么成功执行最后一个.then(),或者触发失败.catch(),在某些情况下,你想要无论Promise成功还是失败,运行相同的代码,例如清除,删除对话,关闭数据库连接等等。
.finally()允许你指定一个最终的逻辑而不是在最后重复.then(),和.catch():
function doSomething() {
doSomething1()
.then(doSomething2)
.then(doSomething3)
.catch(err => {
console.log(err);
})
.finally(()=>{
//finish here!
});
}
Rest/Spread属性
ES2015引入了Rest参数和扩展运算符。三点(…)表示法仅用于数组操作。Rest参数语法将传递给函数的最后一个参数转换为数组:
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, 49, 17];
console.log(Math.max(...values));//100
ES2018支持对象解构和数组类似的Rest/Spread扩展功能。一基本的例子:
const myObj = {
a: 1,
b: 2,
c: 3
};
const {a, ...x} = myObj;
//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: 5};
//obj2 = {a: 1, b: 2, c: 3, z: 5}
您可以使用Spread运算符来克隆对象(obj2 = { …obj1 });
正则表达式命名为捕获组
JavaScript正则表达式可以返回匹配对象~一个包含匹配字符串的类数组。例如,要以YYYY-MM-DD格式解析日期:
const
reDate = /([0-9]{4})-([0-9]{2}-([0-9]{2})/,
matchs = reDate.exec('2018-12-30'),
year = matchs[1],//2018
month = matchs[2],//12
day = matchs[3];//30
它很难阅读,并且更改正则表达式也可能会更改匹配对象索引。
ES2018允许在开始捕获括号(
后立即使用符号?<name>,如下:
const
reDate = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/,
matchs = reDate.exec('2018-12-30'),
year = matchs.groups.year, //2018
month = matchs.groups.month,//12
day = matchs.groups.day; //30
任何未匹配的命名组都将其属性设置为undefined.
命名捕获组也可用于replace()方法中。例如将日期转换为美国MM-DD–YYYY格式:
const
reDate = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/,
d = '2018-12-30',
usDate = d.replace(reDate, '$<month>-$<day>-$<year>');
正则表达式反向断言(lookbehind)
目前JavaScript在正则表达式中支持先行断言(lookahead)。这意味着必须进行匹配但不捕获任何内容,并且断言不包含在整个匹配的字符串中,例如从价格中获取货币符号:
const
reLookahead = /\D(?=\d+)/,
matchs = reLookahead.exec('$123.89');
console.log(matchs[0]);//$
ES2018引入以相同方式工作但是匹配前面的反向断言(lookbehind),因此我们可以捕获价格并忽略货币字符:
const
reLookbehind = /(?<=\D)\d+/,
matchs = reLookbehind.exec('$123.89');
console.log(matchs[0]);//123.89
以上是一个肯定反向断言,非数字\D
必须存在。同样的,还存在否行反向断言,表示一个值必须不存在,例如:
const
reLookbehindNeg = /(?<!\D)\d+/,
matchs = reLookbehind.exec('$123.89');
console.log(matchs[0]);//null
正则表达式s(dotAll)标志
正则表达式点.
匹配除回车外的任何单个字符。标志s
改变这中行为,允许行终止符的出现,例如:
/hello.world/.test('hello\nworld'); //false
/hello.world/s.test('hello\nworld'); //true
正则表达式Unicode属性转义
到目前为止,还无法在正则表达式中本机访问Unicode字符属性。ES2018添加了Unicode属性转义-在表单\p{…}和\P{…}-在正则表达式中使用标记u
(unicode)设置,在\p
块内,可以使用键值对的方式设置需要匹配的属性而非具体的内容。例如:
const reGreekSymbol = /\p{Script=Greek}/u;
reGreekSymbol.test('π');//true
此特性可以避免使用特定的Unicode区间来进行内容类型判断,提升可读性和可维护性。
非转义序列的模板字符串
最后,ES2018删除了与模板字符串中转义序列相关的所有语法限制。
以前,一个\u
开始一个unicode转义,\x
开始一个十六进制转义,\
后跟一个数字开始一个八进制转义。这使得无法创建某些字符串,如Window文件路径c:\uuu\xxx\111。更多细节参考模板字符串。