ES2018 重点总结

1.for await of

(1)for await of和for…of的对比及使用

for…of循环用于遍历同步的 Iterator 接口,for await…of循环用于遍历异步的 Iterator 接口。

function Gen (time) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve(time)
    }, time)
  })
}

// for ... of
async function test1 () {
  let arr = [Gen(2000), Gen(100), Gen(3000)]
  for (let item of arr) {
    console.log(Date.now(), await item.then(console.log))
  }
}

test1()
// 2000
// 1616227047645 undefined
// 100
// 1616227049650 undefined
// 3000
// 1616227049651 undefined


// for await of
async function test () {
  let arr = [Gen(2000), Gen(100), Gen(3000)]
  for await (let item of arr) {
    console.log(Date.now(), item)
  }
}

test()
// 1616225851505 2000
// 1616225851506 100
// 1616225852505 3000

(2)数据结构自定义异步遍历器

自定义异步遍历器其实和自定义同步遍历器有很多相似之处:

异步可迭代协议
如果让一个对象是可遍历的,就要遵守异步可迭代协议,该协议要求
1.对象要部署一个以 Symbol.asyncIterator为 key 的键值对
(同步实现的是Symbol.iterator)
2. value 就是一个要遵守迭代器协议的无参函数


迭代器协议
迭代器协议要求符合以下条件:
1.一个对象需包含一个无参函数 next
2.next 返回值也是一个对象,包含 done 和 value 属性。
其中 done 表示遍历是否结束,value 返回当前遍历的值。

2.Promise.prototype.finally()

finally()方法用于指定不管 Promise 对象最后状态如何,在执行完then或catch指定的回调函数以后,都会执行的操作。常用于关闭数据库连接等操作。

finally方法的回调函数不接受任何参数,finally方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。

promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});

3.对象的扩展运算符 …

(1)解构赋值

解构赋值用于从一个对象取值,相当于将目标对象自身的所有可遍历的(enumerable)、但尚未被读取的属性,分配到指定的对象上面。

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }

(2)扩展运算符

对象的扩展运算符(…)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。

const input = {
  a: 1,
  b: 2
}

const output = {
  ...input,
  c: 3
}

console.log(output) // {a: 1, b: 2, c: 3}

4.正则的扩展

(1)s 修饰符:dotAll 模式

正则表达式中,点(.)是一个特殊字符,代表任意的单个字符,但是有两个例外。
一个是四个字节的 UTF-16 字符,这个可以用u修饰符解决;
另一个是行终止符(line terminator character)。

所谓行终止符,就是该字符表示一行的终结。以下四个字符属于“行终止符”。
U+000A 换行符(\n)
U+000D 回车符(\r)
U+2028 行分隔符(line separator)
U+2029 段分隔符(paragraph separator)

(1)字符

s修饰符,使得.可以匹配任意单个字符。 这被称为dotAll模式,即点(dot)代表一切字符。

foo.bar/.test('foo\nbar') // false
/foo.bar/s.test('foo\nbar') // true
(2)属性

正则表达式还引入了一个dotAll属性,返回一个布尔值,表示该正则表达式是否处在dotAll模式。

const re = /foo.bar/s;
re.test('foo\nbar') // true
re.dotAll // true
re.flags // 's'

(2)具名组匹配 named capture groups

// match
const str = '2021-03-20'
const reg = /(\d{4})-(\d{2})-(\d{2})/
console.log(str.match(reg))
//  ["2021-03-20", "2021", "03", "20", index: 0, input: "2021-03-20", groups: undefined]

// index [匹配的结果的开始位置]
// input [搜索的字符串]
// groups [一个捕获组数组 或 undefined(如果没有定义命名捕获组)]



// exec
const matchObj = reg.exec(str);
const year = matchObj[1]; // 2021
const month = matchObj[2]; // 03
const day = matchObj[3]; // 20

// 组匹配的一个问题是,每一组的匹配含义不容易看出来,而且只能用数字序号
//(比如matchObj[1])引用,要是组的顺序变了,引用的时候就必须修改序号。

// 具名组匹配(Named Capture Groups),允许为每一个组匹配指定一个名字,既便于阅读代码,又便于引用
const REG = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const matchObj = REG.exec('2021-03-20');
const year = matchObj.groups.year; // "2021"
const month = matchObj.groups.month; // "03"
const day = matchObj.groups.day; // "20"
// “具名组匹配”在圆括号内部,模式的头部添加“问号 + 尖括号 + 组名”
// (如?<year>),然后就可以在exec方法返回结果的groups属性上引用该组名。
// 同时,数字序号(matchObj[1])依然有效。

let t = '2021-03-20'.match(REG)
console.log(t.groups.year) // 2021
console.log(t.groups.month) // 03
console.log(t.groups.day) // 20

(3)后行断言

在 ES2018 之前 JavaScript 正则只支持先行断言,不支持后行断言。

(?<…)是后行断言的符号,(?..)是先行断言的符号然后结合 =(等于)、!(不等)、\1(捕获匹配)。

先行断言&先行否定断言

“先行断言”指的是,x只有在y前面才匹配,必须写成/x(?=y)/
“先行否定断言”指的是,x只有不在y前面才匹配,必须写成/x(?!y)/。

let test = 'hello123helloworld'
// 先行断言:匹配hello,但其后面必须是123
console.log(test.match(/hello(?=123)/))
// ["hello", index: 0, input: "hello123helloworld", groups: undefined]

// 先行否定断言:匹配hello,但后面必须不是123
console.log(test.match(/hello(?!123)/))
// ["hello", index: 8, input: "hello123helloworld", groups: undefined]
后行断言&后行否定断言

“后行断言”正好与“先行断言”相反,x只有在y后面才匹配,必须写成/(?<=y)x/。
“后行否定断言”则与“先行否定断言”相反,x只有不在y后面才匹配,必须写成/(?<!y)x/。

let test = 'hello123helloworld'
// 后行断言:匹配hello,但前面必须是123
console.log(test.match(/(?<=123)hello/))
// ["hello", index: 8, input: "hello123helloworld", groups: undefined]

// 后行否定断言:匹配hello,但前面必须不是123
console.log(test.match(/(?<!123)hello/))
// ["hello", index: 0, input: "hello123helloworld", groups: undefined]

(4)Unicode 属性类

Unicode 属性类\p{key=value}要指定属性名和属性值,从而允许正则表达式匹配一类字符组。(对于某些属性,可以只写属性名,或者只写属性值。)
根据 Unicode 规范,每一个 Unicode 字符除了有唯一的码点,还具有其它属性它们是:Unicode Property、Unicode Block、Unicode Script。

\P{…}是\p{…}的反向匹配,即匹配不满足条件的字符。

这两种类只对 Unicode 有效,所以使用的时候一定要加上u修饰符。如果不加u修饰符,正则表达式使用\p和\P会报错。

例如:\p{Script=Greek}指定匹配希腊文字母 或 匹配所有数字

// 匹配希腊文字母
const regexGreekSymbol = /\p{Script=Greek}/u;
regexGreekSymbol.test('π') // true

// 匹配所有数字
const regex = /^\p{Number}+$/u;
regex.test('²³¹¼½¾') // true
regex.test('㉛㉜㉝') // true
regex.test('ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ') // true
字符编码包括 ASCII 和 Unicode,文件编码包括 UTF-8、GBK等。
文件编码和字符编码没有关系,即使指定了文件编码,字符变也可以灵活选择而不受任何限制。
Unicode Property

按照字符的功能对字符进行分类,一个字符只能属于一个 Unicode Property。

可以将Unicode property 理解为字符组,在正则中用 /p{属性类型} 表示。
例如p属性的字符组和P属性的字符组,将小写 p 改成大写,就是该字符组的排除型字符组。
想想看 \d 匹配 0-9 这个字符组,而\D 匹配 0-9 以外的字符组。

let input = 'abcdAeCd中国'
console.log(input.match(/\p{L}/ug))
// ["a", "b", "c", "d", "A", "e", "C", "d", "中", "国"]

// 这段代码的含义是在输入中匹配所有的字符(不限语言)
// 这里使用的是 Unicode Property:{L}
// 这个属性的含义是任何语言的任何字母。它有点等同于:
let input = 'abcdAeCd中国'
console.log(input.match(/./sg))
// ["a", "b", "c", "d", "A", "e", "C", "d", "中", "国"]

// 其它类型:
// {Ll} [任何具有大写字母的小写字母]
// {N} [任何语言下的数字]

更多属性详见

Unicode Script

按照字符所属的书写系统来划分字符,它一般对应某种语言。比如 \p{Script=Greek} 表示希腊语,\p{Script=Han} 表示汉语。
我们只需要在 Unicode Scripts 找到对应的名称即可,而不需要自己去计算所有对应语言字符的的 Unicode 范围。

before:

let input = `I'm chinese!我是中国人`
console.log(input.match(/[\u4e00-\u9fa5]+/))
// ["我是中国人", index: 12, input: "I'm chinese!我是中国人", groups: undefined]

after:

let input = `I'm chinese!我是中国人`
console.log(input.match(/\p{Script=Han}+/u))
// ["我是中国人", index: 12, input: "I'm chinese!我是中国人", groups: undefined]
Unicode Block

将 Unicode 字符按照编码区间进行划分,所以每一个字符都只属于一个 Unicode Block,举例说明:

\p{InBasic_Latin}: U+0000–U+007F
\p{InLatin-1_Supplement}: U+0080–U+00FF
\p{InLatin_Extended-A}: U+0100–U+017F
\p{InLatin_Extended-B}: U+0180–U+024F

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值