ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

17.(ECMAScript)es11完全解读

2021-02-18 16:57:32  阅读:194  来源: 互联网

标签:const log 17 Promise ECMAScript regExp console es11 match


文章目录

1. 重点提炼

  • String扩展
  • 动态导入
  • BigInt
  • Promise.allSettled()
  • 全局对象——globalThis
  • 可选链
  • 空值合并运算符

2. 字符串扩展

  • 全局模式捕获:String.prototype.matchAll()

在正则表达式中经常使用match,匹配正则。


2.1 定义一个html模版的字符串。 => 需求:获取div标签中的内容。

定义一个html模版的字符串。 => 需求:获取div标签中的内容。


2.1.1 exec g实现

如何用一个正则表达式来得到所有匹配项,可以使用execg修饰符,如果正则表达式有/g标志,那么多次调用.exec()就会得到所有匹配的结果。 如果没有匹配的结果,.exec()就会返回null。在这之前会返回每个匹配的匹配对象。 这个对象包含捕获的子字符串和更多信息。

即在正则中首先会想到exec方法,即执行,可以对某个字符串进行正则匹配,并且可以结合g修饰符,进行全局匹配。

封装一个方法,其第一个参数是正则表达式,第二个参数是对应目标字符串。

const str = `
    <html>
        <body>
            <div>第一个div</div>
            <p>这是p</p>
            <div>第二个div</div>
            <span>这是span</span>
            <div>第三个div</div>
        </body>
    </html>
`
// exec g
function selectDiv(regExp, str){
    let matches = [] // 输出匹配结果数组
    while(true){
        const match = regExp.exec(str)
        // 未匹配上
        if(match == null){
            break
        }
        matches.push(match)
    }
    return matches
}
const regExp = /<div>(.*)<\/div>/g
const res = selectDiv(regExp, str)
console.log(res)

其返回的数组第0个,是整个文本匹配的结果,即未分组前的整体。从第1个开始就是子表达式匹配的结果了,即分组。

image-20201130114107715

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.12
Branch: branch02

commit description:a4.12(字符串扩展——exec使用1)

tag:a4.12


因此如果需要获取div标签里的内容,即该分组,应该获取下标为1的数组。

function selectDiv(regExp, str){
    let matches = [] // 输出匹配结果数组
    while(true){
        // console.log(regExp.lastIndex)
        const match = regExp.exec(str)
        // console.log(match)
        // 未匹配上
        if(match == null){
            break
        }
        matches.push(match[1])
    }
    return matches
}
const regExp = /<div>(.*)<\/div>/g
const res = selectDiv(regExp, str)
console.log(res)

image-20201130120531524

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.13
Branch: branch02

commit description:a4.13(字符串扩展——exec使用2)

tag:a4.13


2.1.2 /g作用

注意:如果不全局匹配 =>

const regExp = /<div>(.*)<\/div>/

如上代码会陷入死循环,因为不是全局匹配,则每一次都是从字符串的开头进行匹配,则match永远不可能是null,则陷入死循环。

实际正则表达式中存在一个lastIndex属性(初始值为0),每次执行exec的时候,实际是根据lastIndex属性值去执行(从该属性的位置开始执行,即决定开始匹配的位置)。如果正则表达式没有/g标志,那么运行一次.exec()时,不会改变lastIndex的值,导致下一次运行exec()时,匹配仍旧是从字符串0的位置开始。当正则表达式加了/g标志后,运行一次exec(),正则表达式的lastIndex就会改变,下次运行exec()就会从前一次的结果之后开始匹配。

不过如果没有使用/g的正则模式,.match 的效果和RegExp.prototype.exec()是一致的。

const str = `
    <html>
        <body>
            <div>第一个div</div>
            <p>这是p</p>
            <div>第二个div</div>
            <span>这是span</span>
            <div>第三个div</div>
        </body>
    </html>
`
// exec g
function selectDiv(regExp, str){
    let matches = [] // 输出匹配结果数组
    while(true){
        console.log(regExp.lastIndex)
        const match = regExp.exec(str)
        console.log(match)
        // 未匹配上
        if(match == null){
            break
        }
        matches.push(match[1])
    }
    return matches
}
const regExp = /<div>(.*)<\/div>/g
const res = selectDiv(regExp, str)
console.log(res)

第一次从0的位置开始找,然后匹配上了第一个div;这个时候字符是第39个,然后隔了17个字符(找到的部分),下一次则从39+17=56的位置开始找;然后依次往下开始找,一直找到头。

故如果没有全局匹配,每一次的lastIndex都是0

image-20201130121628458

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.14
Branch: branch02

commit description:a4.14(字符串扩展——lastIndex属性)

tag:a4.14


2.1.3 match实现

如果用 .match 方法结合/g 的正则模式,将会把所有的匹配打包成一个数组返回,换句话说所有的捕获被忽略。

const str = `
    <html>
        <body>
            <div>第一个div</div>
            <p>这是p</p>
            <div>第二个div</div>
            <span>这是span</span>
            <div>第三个div</div>
        </body>
    </html>
`

const regExp = /<div>(.*)<\/div>/g

// match
console.log(str.match(regExp))

match方法也可进行匹配,但是和需求则有一些的出入,需求不用div标签,仅仅是div标签中的内容。

match的作用就是找到包含的结果,而exec可以设置子表达式,即捕获组,打算match方法不行。

image-20201130122235187

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.15
Branch: branch02

commit description:a4.15(字符串扩展——match)

tag:a4.15


2.1.4 replace实现

可以使用一个技巧通过.replace() 收集捕获,我们使用一个函数来计算替换值。

const str = `
    <html>
        <body>
            <div>第一个div</div>
            <p>这是p</p>
            <div>第二个div</div>
            <span>这是span</span>
            <div>第三个div</div>
        </body>
    </html>
`

const regExp = /<div>(.*)<\/div>/g

// replace
function selectDiv(regExp, str){
    let matches = []
    str.replace(regExp, (all, first) => {
        matches.push(first)
    })
    return matches
}
const res = selectDiv(regExp, str)
console.log(res)

image-20201130122901387

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.16
Branch: branch02

commit description:a4.16(字符串扩展——replace)

tag:a4.16


replace方法的第一个参数可以是正则的规则,第二个参数是一个回调函数,或者一般都是用一个固定的字符串。

回调函数第一个参数,是完整的匹配结果,第二个参数是第一个子表达式的结果(如果有多个则依次类推),和exec有些类似。

第三个参数 是offset , 匹配到的子字符串在原字符串中的偏移量。(比如,如果原字符串是 'abcd',匹配到的子字符串是 'bc',那么这个参数将会是 1

第四个参数string,被匹配的原字符串。

官网例子 =>

[^\d]* => 非数字(匹配多次)

\d* => 数字(匹配多次)

[^\w]* => 非数字、字母、下划线(匹配多次)

function replacer(match, p1, p2, p3, offset, string) {
  // p1 is nondigits, p2 digits, and p3 non-alphanumerics
  return [p1, p2, p3].join(' - ');
}
var newString = 'abc12345#$*%'.replace(/([^\d]*)(\d*)([^\w]*)/, replacer);
console.log(newString);  // abc - 12345 - #$*%

2.1.5 matchAll

最为简洁的方式 =>es11 => matchAll

str.matchAll(regexp)

matchAll() 方法返回一个包含所有匹配正则表达式及分组捕获结果的迭代

参数含义必选
regexp正则表达式对象Y

根据正则匹配字符串中所有的匹配项得出结果并返回一个迭代器,利用for…of迭代。

注意

  1. 如果所传参数不是一个正则表达式对象,则会隐式地使用new RegExp(obj)将其转换为一个 RegExp
  2. 返回值一个迭代器,但是不可重用,结果耗尽需要再次调用方法,获取一个新的迭代器
const str = `
    <html>
        <body>
            <div>第一个div</div>
            <p>这是p</p>
            <div>第二个div</div>
            <span>这是span</span>
            <div>第三个div</div>
        </body>
    </html>
`

const regExp = /<div>(.*)<\/div>/g

// matchAll
function selectDiv(regExp, str){
    let matches = []
    for(let match of str.matchAll(regExp)){
        matches.push(match[1])
    }
    return matches
}
const res = selectDiv(regExp, str)
console.log(res)

实际和exec g 方法类似,但是更为简洁。

image-20201130123625538

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.17
Branch: branch02

commit description:a4.17(字符串扩展——matchAll)

tag:a4.17


报错,matchAll要求必须有全局的匹配参数,即要求必须写g,因此该方法更为安全,不容易死循环。

因此在项目中,如果有需求需要用正则匹配字符串中所有的匹配项,强烈推荐使用matchAll

const regExp = /<div>(.*)<\/div>/

image-20201130124217836

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.18
Branch: branch02

commit description:a4.18(字符串扩展——matchAll安全性)

tag:a4.18


3. 动态导入:Dynamic import()

按需 import提案几年前就已提出,如今终于能进入ES正式规范。这里个人理解成“按需”更为贴切。现代前端打包资源越来越大,打包成几MJS资源已成常态,而往往前端应用初始化时根本不需要全量加载逻辑资源,为了首屏渲染速度更快,很多时候都是按需加载,比如懒加载图片等。而这些按需执行逻辑资源都体现在某一个事件回调中去加载。


=> 按需导入,实际就是懒加载。目的就是加快首屏渲染速度,不需要一进页面,加载大量的资源,部分页面可以用户进入的时候再加载资源。

实现 => 点击按钮,再进行导入之前我封装的ajax请求的文件。

ajax是通过export default导出的,因此这里import返回的Promise参数就是该对象,利用default直接调用即可。

const oBtn = document.querySelector('#btn')
oBtn.addEventListener('click', () => {
    import('./ajax').then(mod => {
        console.log(mod)
        mod.default('static/a.json', res => {
            console.log(res)
        })
    })
})

image-20201130150215974

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.19
Branch: branch02

commit description:a4.19(动态导入:Dynamic import())

tag:a4.19


Vue生态圈中经常用到vue-router => 路由懒加载就应用该原理。并且webpack目前已很好的支持了该特性。


4. 新的原始数据类型:BigInt

es11之前,支持的最大整数,是253次方。哪怕对其加1,最后的结果还是253次方。

Number.MAX_SAFE_INTEGER == 2的53次方 - 1

const max = 2 ** 53
console.log(max)

console.log(Number.MAX_SAFE_INTEGER)

console.log(max === max + 1) // true

es11之前,所谓的整型是存在最大数限制的。

image-20201130151033407

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.20
Branch: branch02

commit description:a4.20(新的原始数据类型:BigInt——es11之前,所谓的整型是存在最大数限制的)

tag:a4.20


4.1 数字后面增加n

但如果现在需求,需要更大数字。 => 利用es11引进的新的原始数据类型:BigInt => 数字末尾加n

BigInt,表示一个任意精度的整数,可以表示超长数据,可以超出253次方。

const bigInt = 9007199254740993n
console.log(bigInt)
console.log(typeof bigInt) // bigint

image-20201130153214993

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.21
Branch: branch02

commit description:a4.21(新的原始数据类型:BigInt——基本使用)

tag:a4.21


BigInt数据类型对应小一些数,与正常数组类型对比,两等成立,三等不成立。

即与普通数相比,同样的数值相等但类型不等。

console.log(1n == 1) // true
console.log(1n === 1) // false

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.22
Branch: branch02

commit description:a4.22(新的原始数据类型:BigInt——与普通数相比,同样的数值相等但类型不等)

tag:a4.22


4.2 使用 BigInt 函数

除了直接在数字末尾加n,也可通过BigInt函数传递参数创建BigInt数据。

很大的数也可进行运算,但是出来的结果末尾带n,如果不想要n,可以调用toString方法。

注意:超过范围的数字,只能用字符串存储,用number类型是存不下的。

const bigInt = 9007199254740993n

const bigInt2 = BigInt(9007199254740993n)
console.log(bigInt2)

const num = bigInt + bigInt2
console.log(num.toString())

image-20201130153751555

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.23
Branch: branch02

commit description:a4.23(新的原始数据类型:BigInt——特性)

tag:a4.23


5. Promise扩展:Promise.allSettled()

  • Promise.allSettled()
  • allSettled() vs all()

Promisees6提出,作用是对于异步状态进行管理的,其内有一个静态方法是all,它的作用是,其参数是一个数组,数组里的每一个元素都是一个promise对象,需要等待数组中的所有promise对象都执行完成以后,如果想执行某些逻辑操作,就可将其放在all里。

实际Promise.all存在一些缺陷,满足不了有些应用场景。

它的最大问题就是如果其中某个任务出现异常(reject),所有任务都会挂掉,Promise直接进入 reject状态。

Promise.all([
    Promise.resolve({
        code: 200,
        data: [1, 2, 3]
    }),
    Promise.resolve({
        code: 200,
        data: [4, 5, 6]
    }),
    Promise.resolve({
        code: 200,
        data: [7, 8, 9]
    }),
]).then(res=>{
    console.log(res)
    console.log('成功')
}).catch(err=>{
    console.log(err)
    console.log('失败')
})

image-20201130154728517

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.24
Branch: branch02

commit description:a4.24(Promise扩展——Promise.all都成功)

tag:a4.24


假设以上三次请求,中间的请求是失败的,Promise.all 会认为都是失败的。这样就存在一个问题,请求成功的结果就获取不到的。这种一个请求失败,就导致所有请求失败的需求显然是不太好的。

Promise.all([
    Promise.resolve({
        code: 200,
        data: [1, 2, 3]
    }),
    Promise.reject({
        code: 500,
        data: []
    }),
    Promise.resolve({
        code: 200,
        data: [7, 8, 9]
    }),
]).then(res=>{
    console.log(res)
    console.log('成功')
}).catch(err=>{
    console.log(err)
    console.log('失败')
})

image-20201130155942247

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.25
Branch: branch02

commit description:a4.25(Promise扩展——Promise.all对应一个请求失败)

tag:a4.25


实际最好失败的请求则返回失败,成功的请求也可以返回对应的结果。 => 这种场景就无法使用Promise.all 了。

这就需要一种机制,对于并发任务的处理,不管哪个是成功的?还是失败的?我们都可以得到对应的状态。 => Promise.allSettled()

Promise.allSettled([
    Promise.resolve({
        code: 200,
        data: [1, 2, 3]
    }),
    Promise.reject({
        code: 500,
        data: []
    }),
    Promise.resolve({
        code: 200,
        data: [7, 8, 9]
    }),
]).then(res=>{
    console.log(res)
    console.log('成功')
}).catch(err=>{
    console.log(err)
    console.log('失败')
})

虽然并发请求返回三个对象,但是每一个都对应一个promise的状态。

image-20201130160207012

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.26
Branch: branch02

commit description:a4.26(Promise扩展——Promise.allSettled()基本使用)

tag:a4.26


根据不同的状态,可以进行对应逻辑处理。如:只过滤出成功的状态。

Promise.allSettled([
    Promise.resolve({
        code: 200,
        data: [1, 2, 3]
    }),
    Promise.reject({
        code: 500,
        data: []
    }),
    Promise.resolve({
        code: 200,
        data: [7, 8, 9]
    }),
]).then(res=>{
    const data = res.filter(item => item.status === 'fulfilled')
    console.log(data)
}).catch(err=>{
    console.log(err)
    console.log('失败')
})

也可以再对失败的请求,给用户一个提示等等。

image-20201130160536606

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.27
Branch: branch02

commit description:a4.27(Promise扩展——Promise.allSettled()只过滤出成功的状态)

tag:a4.27


6. 全局对象:globalThis

Javascript在不同的环境获取全局对象有不通的方式:

  • 提供了一个标准的方式去获取不同环境下的全局对象
  • node端全局变量 => global
  • web端全局变量 => windowself (打开浏览器创建的窗口其实就是windowself ,这两者是一个东西)

note:self => 打开任何一个网页,浏览器会首先创建一个窗口,这个窗口就是一个window对象,也是js运行所依附的全局环境对象和全局作用域对象。self指窗口本身,它返回的对象跟window对象是一模一样的。也正因为如此,window对象的常用方法和函数都可以用self代替window


self.setTimeout(()=>{
    console.log('es2020')
}, 1000)

es2020

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.28
Branch: branch02

commit description:a4.28(全局对象:globalThis——self)

tag:a4.28


在之前环境中,想要获取任何环境下的全局变量则需要判断。

const getGlobal = () => {
    if (typeof self !== 'undefined') {
        return self
    }
    if (typeof window !== 'undefined') {
        return window
    }
    if (typeof global !== 'undefined') {
        return global
    }
    throw new Error('无法找到全局对象')
}
const global = getGlobal()
console.log(global)

image-20201201092751215

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.29
Branch: branch02

commit description:a4.29(全局对象:globalThis——在之前环境中,想要获取任何环境下的全局变量则需要判断)

tag:a4.29


es11中使用globalThis,在任何环境中都可以获取到全局对象。

globalThis提供了一个标准的方式来获取不同环境下的全局 this对象(也就是全局对象自身)。不像 window或者 self这些属性,它确保可以在有无窗口的各种环境下正常工作。所以,你可以安心的使用 globalThis,不必担心它的运行环境。为便于记忆,你只需要记住,全局作用域中的 this就是 globalThis

console.log(globalThis)

web端

image-20201201092751215

node端

image-20201201093127452

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.30
Branch: branch02

commit description:a4.30(全局对象:globalThis——基本使用)

tag:a4.30


7. 可选链:Optional chaining

在开发当中会有很多对象,对象下面属性可能有很多层,经常需要判断对象下面有没有该属性,之前判断都非常麻烦,有了可选链会更为方便。

即可让我们在查询具有多层级的对象时,不再需要进行冗余的各种前置校验。


在之前的语法中,想获取到深层属性或方法,不得不做的前置校验,否则很容易命中 Uncaught TypeError: Cannot read property... 这种错误,这极有可能让你整个应用挂掉。

调用未知或者后端传来的对象,必须使用如下方式,否则万一属性没有就会报错,这样会非常不安全。

const user = {
    address: {
        street: 'xx街道',
        getNum() {
            return '80号'
        }
    }
}
const street = user && user.address && user.address.street
console.log(street)

const num = user && user.address && user.address.getNum && user.address.getNum()
console.log(num)

image-20201201093608672

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.31
Branch: branch02

commit description:a4.31(可选链:Optional chaining——之前判断方式)

tag:a4.31


可选链 => ?.

可选链中的 ? 表示如果问号左边表达式有值, 就会继续查询问号后面的字段。根据下面可以看出,用可选链可以大量简化类似繁琐的前置校验操作,而且更安全。

// 可选链
const user = {
    address: {
        street: 'xx街道',
        getNum() {
            return '80号'
        }
    }
}

const street = user?.address?.street
console.log(street)
const num = user?.address?.getNum?.()
console.log(num)

image-20201201093608672

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.32
Branch: branch02

commit description:a4.32(可选链:Optional chaining——基本使用)

tag:a4.32


8. 空值合并运算符:Nullish coalescing Operator

空值合并运算符??)是一个 逻辑运算符 。当左侧操作数为 nullundefined时,其返回右侧的操作数。否则返回左侧的操作数。

很多时候需要给某些值设置默认值,经常使用或运算符设置默认值,但是或运算符会有一些缺陷。

因此es11提出空值合并运算符

const b = 2
const a = b || 5
console.log(a)

2

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.33
Branch: branch02

commit description:a4.33(空值合并运算符——或运算符-默认值有值的情况)

tag:a4.33


const b = 0
const a = b || 5
console.log(a)

弊端:0代表false,因此如果值是0,会认为是没值。

注意:一般设置默认值都是为了防止nullundefined。但是如果是false0,也被赋值默认值,这是很大的弊端。

5

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.34
Branch: branch02

commit description:a4.34(空值合并运算符——或运算符-弊端)

tag:a4.34


空值合并运算符?? 我们仅在第一项为 nullundefined时设置默认值

const b = null
const a = b ?? 6
console.log(a)

6

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.35
Branch: branch02

commit description:a4.35(空值合并运算符——null)

tag:a4.35


const b = false
const a = b ?? 6
console.log(a)

false

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a4.36
Branch: branch02

commit description:a4.36(空值合并运算符——false)

tag:a4.36




(后续待补充)

标签:const,log,17,Promise,ECMAScript,regExp,console,es11,match
来源: https://blog.csdn.net/u013946061/article/details/113849445

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有