该篇文章主要是介绍了ES9新加的一些特性。javascript
在async/await
的某些时刻,你可能尝试在同步循环中调用异步函数。例如:java
async function process(array) {
for (let i of array) {
await doSomething(i);
}
}
复制代码
复制代码
这段代码不会正常运行,下面这段一样也不会:正则表达式
async function process(array) {
array.forEach(async i => {
await doSomething(i);
});
}
复制代码
复制代码
这段代码中,循环自己依旧保持同步,并在在内部异步函数以前所有调用完成。数据库
ES2018引入异步迭代器(asynchronous iterators),这就像常规迭代器,除了next()
方法返回一个Promise。所以await
能够和for...of
循环一块儿使用,以串行的方式运行异步操做。例如:数组
async function process(array) {
for await (let i of array) {
doSomething(i);
}
}
复制代码
在ES6中,一个Promise
链要么成功进入最后一个then()
要么失败触发catch()
。而实际中,咱们可能须要不管Promise
不管成功仍是失败,都运行相同的代码。例如清除,删除回话,关闭数据库链接等操做。bash
ES9中,容许使用finally()
来指定最终的逻辑。异步
以下:async
let count = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(100)
}, 1000);
})
}
let list = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve([1, 2, 3])
}, 1000);
})
}
let getList = async () => {
let c = await count()
console.log('async')
let l = await list()
return { count: c, list: l }
}
console.time('start');
getList().then(res => {
console.log(res)
})
.catch(err => {
console.timeEnd('start')
console.log(err)
})
.finally(() => {
console.log('finally')
})
//执行结果
async
{count: 100, list: [1, 2, 3]}
finally
复制代码
在ES6中引入了三点...
,做用主要是Rest参数和扩展运算符
:函数
做用对象仅用于数组post
1.将一个未知数量的参数表示一个数组:
restParam(1, 2, 3, 4, 5);
function restParam(p1, p2, ...p3) {
// p1 = 1
// p2 = 2
// p3 = [3, 4, 5]
}
复制代码
2.扩展运算符:
const values = [99, 100, -1, 48, 16];
console.log( Math.max(...values) ); // 100
复制代码
在ES9中为对象提供了像数组同样的Rest参数和展开运算符。
Rest参数用法
var obj = {
a: 1,
b: 2,
c: 3
}
const { a, ...param } = obj;
console.log(a) //1
console.log(param) //{b: 2, c: 3}
复制代码
Spread用法,用于收集全部的剩余参数:
var obj = {
a: 1,
b: 2,
c: 3
}
function foo({a, ...param}) {
console.log(a);
console.log(param)
}
复制代码
跟数组同样,Rest参数只能在声明的结尾处使用。此外,它只适用于每一个对象的顶层,若是对象中嵌套对象则没法适用。
扩展运算符能够在其余对象内使用
const obj1 = { a: 1, b: 2, c: 3 };
const obj2 = { ...obj1, z: 26 };
// obj2 is { a: 1, b: 2, c: 3, z: 26 }
复制代码
1.浅拷贝
能够利用(...)来进行一个对象的拷贝,可是这种拷贝只能拷贝对象的可枚举自有属性。
var obj = {
name: 'LinDaiDai',
looks: 'handsome',
foo() {
console.log('old');
},
set setLooks(newVal) {
this.looks = newVal
},
get getName() {
console.log(this.name)
}
}
var cloneObj = {...obj};
cloneObj.foo = function() {
console.log('new')
};
console.log(obj)
// { name: 'LinDaiDai',looks: 'handsome', foo: f foo(), get getName:f getName(), set setLooks: f setLooks(newVal)}
console.log(cloneObj)
// { name: 'LinDaiDai',looks: 'handsome', foo: f foo(), getName: undefined, setLooks: undefined }
obj.foo()
// old
cloneObj.foo()
// new
复制代码
如上所示,定义了一个对象obj
并使用(...)
进行对象的拷贝,修改对象内的函数foo()
,并不会影响原有的对象,可是原有对象的setter
和getter
却不能拷贝过去。
2.合并俩个对象
const merged = {...obj1, ...obj2};
//同:
const merged = Object.assign({}, obj1, obj2);
复制代码
Javascript
正则表达式中使用exec()
匹配可以返回一个对象,一个包含匹配字符串的类数组。
以下面案例中的匹配日期格式:
//正则表达式命名捕获组
const reDate = /(\d{4})-(\d{2})-(\d{2})/,
match = reDate.exec('2018-08-06');
console.log(match);
// [2018-08-06, 2018, 08, 06]
// 这样就能够直接用索引来获取年月日:
match[1] // 2018
match[2] // 08
match[3] // 06
复制代码
返回一个数组,数组第0项为与正则表达式相匹配的文本,第 1 个元素是与 RegExpObject 的第 1 个子表达式相匹配的文本(若是有的话),第 2 个元素是与 RegExpObject 的第 2 个子表达式相匹配的文本(若是有的话),以此类推。
上面的案例,如果改变正则表达式的结构就有可能改变匹配对象的索引。
如进行以下修改:
//正则表达式命名捕获组
const reDate = /(\d{2})-(\d{2})-(\d{4})/,
match = reDate.exec('2018-08-06');
console.log(match);
// [2018-08-06, 08, 06, 2018]
// 但此时年月日的索引就改变了
match[3] // 2018
match[1] // 08
match[2] // 06
复制代码
能够看到上面写法的弊端,所以在ES9中容许命名捕获组使用符号?<name>
,以下:
const reDate = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/,
match = reDate.exec('2018-08-06')
console.log(match);
// [2018-08-06, 08, 06, 2018, groups: {day: 06, month: 08, year: 2018}]
//此时可使用groups对象来获取年月日
match.groups.year // 2018
match.groups.month // 08
match.groups.day // 06
复制代码
命名捕获组的写法至关因而把每一个匹配到的捕获组都定义了一个名字,而后存储到返回值的groups
属性中。
replace()
命名捕获也可使用在replace()
方法中。例如将日期转换为美国的 MM-DD-YYYY 格式:
const reDate = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/,
d = '2018-08-06'
USADate = d.replace(reDate, '$<month>-$<day>-$<year>');
console.log(USADate);
// 08-06-2018
复制代码
还能够将中文名的姓和名调换:
const reName = /(?<sur>[a-zA-Z]+)-(?<name>[a-zA-Z]+)/;
Chinese = 'Lin-DaiDai',
USA = Chinese.replace(reName, '$<name>-$<sur>');
console.log(USA);
// DaiDai-Lin
复制代码
先来看下正则表达式先行断言是什么:
如获取货币的符号
const noReLookahead = /\D(\d+)/,
reLookahead = /\D(?=\d+)/,
match1 = noReLookahead.exec('$123.45'),
match2 = reLookahead.exec('$123.45');
console.log(match1[0]); // $123
console.log(match2[0]); // $
复制代码
能够看到如果在正则表达式中加入?=
的话,匹配会发生,但不会有任何捕获,而且断言没有包含在整个匹配字段中。
在ES9中能够容许反向断言:
const reLookahead = /(?<=\D)[\d\.]+/;
match = reLookahead.exec('$123.45');
console.log(match[0]); // 123.45
复制代码
使用?<=
进行反向断言,可使用反向断言获取货币的价格,而忽略货币符号。
上面的案例为确定反向断言,也就是说\D
这个条件必须存在,如果:
const reLookahead = /(?<=\D)[\d\.]+/;
match1 = reLookahead.exec('123.45'),
match2 = reLookahead.exec('12345');
console.log(match1[0]); // 45
console.log(match2); // null
复制代码
能够看到match1
匹配到的是45
,这是因为在123
前面没有任何符合\D
的匹配内容,它会一直找到符合\D
的内容,也就是.
而后返回后面的内容。
而如果没有知足前面确定反向断言的条件的话,则返回null
.
dotAll
模式正则表达式中点.
匹配除回车外的任何单字符,标记s
改变这种行为,容许行终止符的出现:
/hello.world/.test('hello\nworld'); // false
/hello.world/s.test('hello\nworld'); // true
console.log(/hello.world/s.test(`hello
world`)) // true
复制代码
到目前为止,在正则表达式中本地访问 Unicode 字符属性是不被容许的。ES2018添加了 Unicode 属性转义——形式为\p{...}
和\P{...}
,在正则表达式中使用标记 u
(unicode) 设置,在\p
块儿内,能够以键值对的方式设置须要匹配的属性而非具体内容。
const reGreekSymbol = /\p{Script=Greek}/u;
console.log(reGreekSymbol.test('π')); // true
复制代码
Greek
为希腊语的意思。
最后,ES2018 移除对 ECMAScript 在带标签的模版字符串中转义序列的语法限制。
以前,\u
开始一个 unicode 转义,\x
开始一个十六进制转义,\
后跟一个数字开始一个八进制转义。这使得建立特定的字符串变得不可能,例如Windows文件路径 C:\uuu\xxx\111
。更多细节参考模板字符串。
知识产权无价,支持原创。
参考文章:
ES6/ES7/ES8/ES9 能够看到javascript并无让咱们失望,这几年的更新没有落下,不间断的学习,才能保证本身被这个社会淘汰...