function gen (time) {
return new Promise(resolve => {
setTimeout(() => {
resolve(time)
}, time)
})
}
// 并没有等待异步操作执行完毕就执行下一个并输出了——for of解决不了异步遍历的问题
function test1 () {
let arr = [gen(300), gen(100), gen(200)]
for (let item of arr) {
// 输出时间戳和返回的结果
console.log(Date.now(), item.then(console.log))
}
}
test1()
/**
1591166863344 Promise{}
1591166863345 Promise{}
1591166863345 Promise{}
100
200
300
*/
// 这种看似是异步遍历,其实并不理想
async function test2 () {
let arr = [gen(300), gen(100), gen(200)]
for (let item of arr) {
// 输出时间戳和返回的结果
console.log(Date.now(), await item.then(console.log))
}
}
test2()
/**
300
1591166863346 undefined
100
1591166863648 undefined
200
1591166863649 undefined
*/
// for await of 才是异步遍历的最佳选择
async function test3 () {
let arr = [gen(300), gen(100), gen(200)]
for await (let item of arr) {
// 输出时间戳和返回的结果
console.log(Date.now(), item)
}
}
test3()
/**
1591166863649 300
1591166863650 100
1591166863650 200
*/
const obj = {
count: 0,
gen (time) {
return new Promise(resolve => {
setTimeout(() => {
// 这里的返回值要遵循迭代器协议
resolve({ done: false, value: time })
}, time)
})
},
// 异步可迭代协议
[Symbol.asyncIterator] () {
let self = this
return {
// 迭代器协议
next () {
self.count++
if (self.count < 4) {
return self.gen(Math.random() * 1000)
} else {
return Promise.resolve({
done: true,
value: ''
})
}
}
}
}
}
async function test () {
for await (let item of obj) {
console.log(Date.now(), item)
}
}
test()
无论一步执行成功与否,finish都会执行,例如:
const gen = (time) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (time < 500) {
resolve(time)
} else {
reject(time)
}
}, time)
})
}
gen(Math.random() * 1000)
.then(value => console.log('resolve', value))
.catch(err => console.log('reject', err))
.finally(() => console.log('finish'))
const obj = {
a: 1,
b: 2,
c: 3,
d: 4
}
const { a, b, ...rest } = obj
console.log(a, b, rest)
与在数组中使用相比,在对象中需要名称对应
const obj1 = {
a: 1,
b: 2
}
const obj2 = {
c: 3,
d: 4
}
const test = {
...obj1,
...obj2,
e: 5
}
console.log(test)
// 拷贝验证
obj2.c = 30
console.log(obj2)
console.log(test)
在正则中点(.)不支持四个字节的utf16字符 和 行终止符(\n、\r)
// s修饰符:用来让点字符识别行终止符
console.log(/foo.bar/.test('foo\nbar')) // false
console.log(/foo.bar/s.test('foo\nbar')) // true
// u修饰符:用来让点字符识别码点大于0xFFFF的 Unicode 字符
console.log(/^.$/.test('')) // false
console.log(/^.$/u.test('')) // true
console.log(/^.$/.test('\uD842\uDFB7')) // false
console.log(/^.$/u.test('\uD842\uDFB7')) // true
// 检测dotAll是否开启
const re = /^.$/s
console.log(re.flags, re.dotAll) // s true
拓展:
const t1 = '2020-06-03'.match(/(\d{4})-(\d{2})-(\d{2})/)
console.log(t1)
// ["2020-06-03", "2020", "06", "03", index: 0, input: "2020-06-03", groups: undefined]
// 分别对应:完整匹配,分组匹配(多个),匹配到的首位索引,完整的输入字符串,groups
console.log(t1[0]) // 完整匹配
console.log(t1[1]) // 分组匹配
console.log(t1[2]) // 分组匹配
console.log(t1[3]) // 分组匹配
// 命名分组捕获
const t2 = '2020-06-03'.match(/(?\d{4})-(?\d{2})-(?\d{2})/ )
console.log(t2)
console.log(t2.groups.year)
console.log(t2.groups.month)
console.log(t2.groups.day)
console.log(t2.year)
console.log(t2.month)
console.log(t2.day)
const str = 'hello world'
// 先行断言:遇到一个条件,就紧接着直接判断后面是否有符合规则
console.log(str.match(/hello(?=\sworld)/)) // ["hello", index: 0, input: "hello world", groups: undefined]
// 后行断言:遇到一个条件,往回找判断前面是否有符合规则
console.log(str.match(/(?<=hello\s)world/)) // ["world", index: 6, input: "hello world", groups: undefined]
还支持不等于判断
'$foo %foo foo'
字符串中前面是$
符号的foo
替换成bar
console.log('$foo %foo foo'.replace(/(?<=\$?)foo/, 'bar'))
'$1 is worth about ¥7'
字符串中的美元数console.log('$1 is worth about ¥7'.match(/(?<=\$?)\d/)[0])