likes
comments
collection

你不容错过的JavaScript高级语法(四)

作者站长头像
站长
· 阅读数 13

众所周知,js在前端开发中的地位。学好它,真的很重要。

es7

Array.prototype.includes

  • 判断数组中是否包含该元素。
  • 参数一查询的字符串,参数二开始查找的下标。默认是0。 以前的判断方式indexOf
    const names = ["zh", "llm", NaN]

    if (names.indexOf("zh") !== -1) {
      console.log("包含zh元素")
    }

缺点不能判断NaN == NaNincludes是认为NaN == NaN


if (names.indexOf(NaN) !== -1) {// false
  console.log("包含NaN")
}

if (names.includes(NaN)) { // true
  console.log("包含NaN")
}

指数(乘方) exponentiation运算符

在ES7之前,计算数字的乘方需要通过 Math.pow 方法来完成。

在ES7中,增加了 ** 运算符,可以对数字来计算乘方。

    const result1 = Math.pow(3, 3)
    // ES7: **
    const result2 = 3 ** 3

es8

Object.values

之前我们可以通过 Object.keys 获取一个对象所有的key,在ES8中提供了 Object.values 来获取所有的value值。

    const obj = {
      name: "zh",
      age: 22
    }

    console.log(Object.keys(obj)) // [ 'name', 'age' ]
    console.log(Object.values(obj)) // [ 'zh', 22 ]

如果传入一个数组,那么它将返回数组本身

    // 用的非常少
    console.log(Object.values(["zh", "llm"]))

如果传入一个字符串,那么它将返回由每个字符组成的数组。等同于str.split("")

    console.log(Object.values("zh"))// [ 'z', 'h' ]
    console.log("zh".split("")) // [ 'z', 'h' ]

Object.entries

通过Object.entries 可以获取到一个数组,数组中会存放可枚举属性的键值对数组。

    const obj = {
      name: "zh",
      age: 22
    }

    console.log(Object.entries(obj)) // [ [ 'name', 'zh' ], [ 'age', 22 ] ]
    const objEntries = Object.entries(obj)
    objEntries.forEach(item => {
      console.log(item[0], item[1])
    })

如果传入一个数组或者字符串,那么将返回下标和元素组成的entries。

console.log(Object.entries(["zh", "llm"])) //[ [ '0', 'zh' ], [ '1', 'llm' ] ]
console.log(Object.entries("zh")) // [ [ '0', 'z' ], [ '1', 'h' ] ]

String.prototype.padStart / padEnd

某些字符串我们需要对其进行前后的填充,来实现某种格式化效果,ES8中增加了 padStartpadEnd 方法,分别是对字符串的首尾进行填充的。

  • 参数一填充的最大长度,参数二填充的字符。默认是空格填充。
    const message = "Hello World"
    const newMessage = message.padStart(15, "*").padEnd(20, "-")
    console.log(newMessage) // ****Hello World-----
  • 如果填充的最大长度小于原字符串的长度,那么将会输出原字符串。
    const message = "Hello World"
    console.log(message.padStart(1, 0)) //Hello World
  • 如果用来补全的字符串与原字符串,两者的长度之和超过了最大长度,则会截去超出位数的补全字符串。
    '12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12"
    '09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"

我们简单具一个应用场景:比如需要对身份证、银行卡的前面位数进行隐藏:

    const cardNumber = "321324234242342342341312"
    const lastFourCard = cardNumber.slice(-4)
    const finalCard = lastFourCard.padStart(cardNumber.length, "*")
    console.log(finalCard) // ********************1312

es10

Array.prototype.flat

将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数组没有影响。

  • 参数,表明需要展开多少层的数组。默认值为1。
    [1, 2, [3, [4, 5]]].flat() // [1, 2, 3, [4, 5]]

    [1, 2, [3, [4, 5]]].flat(2) // [1, 2, 3, 4, 5]
  • 如果不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数。
    [1, [2, [3]]].flat(Infinity) // [1, 2, 3]
  • 如果原数组有空位,flat()方法会跳过空位。
    [1, 2, , 4, 5].flat() // [1, 2, 4, 5]

Array.prototype.flatMap

他就是mapflat的结合体。相当于执行map(),然后对返回值组成的数组执行flat()方法。该方法返回一个新数组,不改变原数组。

  • 参数一一个遍历函数, 参数二绑定遍历函数里面的this值。
  • 他只能展开一层数组。
    const messages = ["Hello World", "hello zh"]
    const words = messages.flatMap(item => {
      return item.split(" ")
    })

    console.log(words) //[ 'Hello', 'World', 'hello', 'zh' ]

Object.fromEntries

我们可以通过 Object.entries 将一个对象转换成 entries,那么如果我们有一个entries了,如何将其转换成对象呢?

ES10提供了 Object.formEntries来完成转换。

    const obj = {
      name: "zh",
      age: 22
    }

    const entries = Object.entries(obj)
    const newObj = Object.fromEntries(entries)
    console.log(newObj) //{ name: 'zh', age: 22 }

那么这个方法有什么应用场景呢?

将查询字符串转化成一个对象。

    const queryString = 'name=zh&age=22'
    const queryParams = new URLSearchParams(queryString) // 返回一个可迭代对象
    console.log(queryParams) //{ 'name' => 'zh', 'age' => '22' }

    const paramObj = Object.fromEntries(queryParams)
    console.log(paramObj)

String.prototype.trimStart / trimEnd

它们的行为与trim()一致,trimStart()消除字符串头部的空格(tab 键、换行符等不可见的空白符号),trimEnd()消除尾部的空格(tab 键、换行符等不可见的空白符号)。它们返回的都是新字符串,不会修改原始字符串。

trimLeft()trimStart()的别名,trimRight()trimEnd()的别名。

es11

BigInt

在早期的JavaScript中,我们不能正确的表示过大的数字。大于MAX_SAFE_INTEGER的数值,表示的可能是不正确的。

    const maxInt = Number.MAX_SAFE_INTEGER
    console.log(maxInt) // 9007199254740991
    console.log(maxInt + 1) //9007199254740992
    console.log(maxInt + 2) // 9007199254740992 // 出现错误

那么ES11中,引入了新的数据类型BigInt,用于表示大的整数。BitInt的表示方法是在数值的后面加上n。

    const bigInt = 900719925474099100n
    console.log(bigInt + 10n)

当BigInt类型的数字和Number类型的数字运算时,BigInt不会隐私转化,所以在运算之前,我们需要手动转换他们的类型。

    const num = 100
    console.log(bigInt + BigInt(num))

    const smallNum = Number(bigInt)
    console.log(smallNum)

??空值合并操作符

在es11之前,我们是通过||来运算的。但是它会存在一些问题。当前面一个运算数为0,""等时,依旧会赋值第二个运算数。

    const foo = 0
    const bar1 = foo || "default value"
    console.log(bar1) // default value

所以接下来我们就可以使用??来进行运算了。只有当前一个运算数为undefined, null时,才会赋值第二个运算数。

    const foo = 0
    const bar1 = foo || "default value"
    const bar2 = foo ?? "defualt value"

    console.log(bar1, bar2) // default value 0

?.可选链

直接在链式调用的时候判断,左侧的对象是否为nullundefined。如果是的,就不再往下运算,而是返回undefined

globalThis

由于在浏览器中,全局对象是window。在nodejs中全局对象是global。

在ES11中对获取全局对象进行了统一的规范:globalThis。不管是在浏览器还是在nodejs中,打印globalThis就获取的是对应的全局对象。

for..in标准化

在ES11之前,虽然很多浏览器支持for...in来遍历对象类型,但是并没有被ECMA标准化。

在ES11中,对其进行了标准化,for...in是用于遍历对象的key的。

es12

FinalizationRegistry

FinalizationRegistry 对象可以让你在对象被垃圾回收时请求一个回调。

FinalizationRegistry 提供了这样的一种方法:当一个在注册表中注册的对象被回收时,请求在某个时间点上调用一个清理回调。(清理回调有时被称为 finalizer )。

你可以通过调用register方法,注册任何你想要清理回调的对象,传入该对象和所含的值。

    const finalRegistry = new FinalizationRegistry((value) => {
      console.log("注册在finalRegistry的对象, 某一个被销毁", value)
    })
    
    let obj = { name: "zh" }
    let info = { age: 22 }

    finalRegistry.register(obj, "obj")
    finalRegistry.register(info, "value")

    obj = null
    info = null

你不容错过的JavaScript高级语法(四) 当注册的对象被销毁时,会调用FinalizationRegistry传入的构造函数。

WeakRefs

如果我们默认将一个对象赋值给另外一个引用,那么这个引用是一个强引用。

如果我们希望是一个弱引用的话,可以使用WeakRef。

    const finalRegistry = new FinalizationRegistry((value) => {
      console.log("注册在finalRegistry的对象, 某一个被销毁", value)
    })

    let obj = { name: "why" }
    let info = new WeakRef(obj)

    finalRegistry.register(obj, "obj")
    obj = null

    setTimeout(() => {
      console.log(info.deref()) //undefined
      console.log(info.deref()?.name) //undefined
      console.log(info.deref() && info.deref().name) //undefined
    }, 10000)

上面代码表示,当obj对象指空的时候,由于info对象是对obj的弱引用,那么obj销毁的时候,那么在堆内存中的对象也会被销毁。所以info获取不到。并且weakRef获取对象中的属性是通过weakRef.deref()来获取的。 当对象销毁时,他的值是undefined。

其他比较重要的es6-es12知识,后期文章会单独介绍。