写在前面的话标准非实际情况。
ECMAScript 2018,ECMA-262 标准版本的第9版(通常称为ES2018或ES9),于 2018 年 6 月完成。
ECMAScript 2018 introduced support for asynchronous iteration via the AsyncIterator protocol and async generators. It also included four new regular expression features: the dotAll flag, named capture groups, Unicode property escapes, and look-behind assertions. Lastly it included rest parameter and spread operator support for object properties.
- Rest(剩余)/Spread(展开) 属性
- Asynchronous iteration (异步迭代)
- Promise.prototype.finally()
- 正则表达式改进
- 先行断言(lookahead) 和 后行断言(lookbehind)
- Unicode 属性转义 \p{…} 和 \P{…}
- 命名捕获组(Named capture groups)
- 正则表达式的 ‘s’ 标志
Rest(剩余) 属性
对象的解构赋值用于从一个对象取值,相当于将目标对象自身的所有可遍历的(enumerable)、但尚未被读取的属性,分配到指定的对象上面。所有的键和它们的值,都会拷贝到新对象上面。但是是浅拷贝。
1 |
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; |
解构赋值必须是最后一个参数,而且等号右边是 undefined或null都会报错
Spread(展开) 属性
对象的扩展运算符(...)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。等同于使用Object.assign()方法。
1
2
3
let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }
Asynchronous iteration (异步迭代)
for...of循环用于遍历同步的 Iterator 接口。新引入的for await...of循环,则是用于遍历异步的 Iterator 接口。
1 |
async function f() { |
上面代码中,createAsyncIterable()返回一个拥有异步遍历器接口的对象,for…of循环自动调用这个对象的异步遍历器的next方法,会得到一个 Promise 对象。await用来处理这个 Promise 对象,一旦resolve,就把得到的值(x)传入for…of的循环体。
Promise.prototype.finally()
finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。finally方法的回调函数不接受任何参数,因此finally方法里面的操作,应该是与状态无关的
1 |
promise |
finally的简单实现
1
2
3
4
5
6
7
Promise.prototype.finally = function (callback) {
let P = this.constructor;
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
);
};
正则表达式改进
先行断言(lookahead) 和 后行断言(lookbehind)
JavaScript 语言的正则表达式,只支持先行断言(lookahead)和先行否定断言(negative lookahead),该版本引入后行断言(lookbehind)和后行否定断言(negative lookbehind)。
- “先行断言”指的是,
x只有在y前面才匹配,必须写成/x(?=y)/。 - “先行否定断言”指的是,
x只有不在y前面才匹配,必须写成/x(?!y)/。 - “后行断言”正好与“先行断言”相反,
x只有在y后面才匹配,必须写成/(?<=y)x/。 - “后行否定断言”则与“先行否定断言”相反,
x只有不在y后面才匹配,必须写成/(?<!y)x/。
先行断言 先行否定断言
1
2
/\d+(?=%)/.exec('100% of US presidents have been male') // ["100"]
/\d+(?!%)/.exec('that’s all 44 of them') // ["44"]
后行断言 后行否定断言
1
2
/(?<=\$)\d+/.exec('Benjamin Franklin is on the $100 bill') // ["100"]
/(?<!\$)\d+/.exec('it’s is worth about €90') // ["90"]
Unicode 属性转义 \p{…} 和 \P{…}
\p{...}允许正则表达式匹配符合 Unicode 某种属性的所有字符,\P{...}匹配不满足条件的字符。这两种类只对 Unicode 有效,所以使用的时候一定要加上u修饰符。如果不加u修饰符,正则表达式使用\p和\P会报错。
匹配一个希腊文字母
1
2
const regexGreekSymbol = /\p{Script=Greek}/u;
regexGreekSymbol.test('π') // true
Unicode 属性类要指定属性名和属性值。
1
\p{UnicodePropertyName=UnicodePropertyValue}
对于某些属性,可以只写属性名,或者只写属性值。
1
2
\p{UnicodePropertyName}
\p{UnicodePropertyValue}
1 |
/^\p{Script=Greek}+$/u.test('ελληνικ?') // true |
具体有哪些属性和属性值可以提案上查看所有属性:tc39/proposal-regexp-unicode-property-escapes
具名组匹配(Named capture groups)
允许为每一个组匹配指定一个名字,既便于阅读代码,又便于引用。
1 |
const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/; |
具名组匹配等于为每一组匹配加上了 ID,便于描述匹配的目的。如果组的顺序变了,也不用改变匹配后的处理代码。同时,数字序号(matchObj[1])依然有效。
解构赋值
1 |
let {groups: {one, two}} = /^(?<one>.*):(?<two>.*)$/u.exec('foo:bar'); |
解构替换
1
2
3
let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
'2015-01-02'.replace(re, '$<day>/$<month>/$<year>') // '02/01/2015'
replace方法的第二个参数也可以是函数具体用法查看更多信息。
正则表达式的 ‘s’ 修饰符
ES2018 引入s修饰符,使得.可以匹配任意单个字符。这被称为dotAll模式,即点(dot)代表一切字符。
1 |
/foo.bar/s.test('foo\nbar') // true |