文章目錄
一、for await of——異步遍歷
1.集合異步遍歷
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{<pending>}
1591166863345 Promise{<pending>}
1591166863345 Promise{<pending>}
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
*/
2.自定義可遍歷數據結構異步遍歷
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()
二、Promise.finally
無論一步執行成功與否,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'))
三、Object.rest&spread——對象合併(類淺拷貝)
1.rest
const obj = {
a: 1,
b: 2,
c: 3,
d: 4
}
const { a, b, ...rest } = obj
console.log(a, b, rest)
與在數組中使用相比,在對象中需要名稱對應
2.spread
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)
四、RegExp新增
1.dotAll
在正則中點(.)不支持四個字節的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
拓展:
2.命名分組捕獲
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(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\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)
之前:
之後:
3.後行斷言
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])