knzn.net

13 ES7-ES12 知识点解析

在 ES7 之前,如果我们想判断一个数组中是否包含某个元素,需要通过 indexOf 获取结果,并且判断是否为 -1。在 ES7 中,我们可以通过 includes 来判断一个数组中是否包含一个指定的元素,根据情况,如果包含则返回 true, 否则返回 false。

ES7 - Array Includes

const names = ['abc', 'cba', 'nba', 'mba', NaN]

if (names.indexOf('cba') !== -1) {
  console.log('包含abc元素')
}

// ES7 ES2016
// 指定查找的起始位置
if (names.includes('cba', 2)) {
  // false
  console.log('包含abc元素')
}

// indexOf 会忽略 NaN
if (names.indexOf(NaN) !== -1) {
  // false
  console.log('包含NaN')
}

// includes 可以检测到 NaN
if (names.includes(NaN)) {
  console.log('包含NaN')
}

ES7 –指数(乘方) exponentiation 运算符

在 ES7 之前,计算数字的乘方需要通过 Math.pow 方法来完成。在 ES7 中,增加了 ** 运算符,可以对数字来计算乘方。

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

ES8 Object values

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

const obj = {
  name: 'why',
  age: 18,
}

console.log(Object.keys(obj))
console.log(Object.values(obj)) //  ['why', 18]

// 用的非常少
console.log(Object.values(['abc', 'cba', 'nba'])) // ['abc', 'cba', 'nba']
console.log(Object.values('abc')) // ['a', 'b', 'c']

ES8 Object entries

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

const obj = {
  name: 'why',
  age: 18,
}

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

console.log(Object.entries(['abc', 'cba', 'nba'])) // [["0","abc"],["1","cba"],["2","nba"]]
console.log(Object.entries('abc')) // [["0","a"],["1","b"],["2","c"]]

ES8 - String Padding

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

第一个参数是,填充后,字符串的长度,如果该参数小于等于字符串的长度,则填充不起作用

const message = 'Hello World'

const newMessage = message.padStart(15, '*').padEnd(20, '-')
console.log(newMessage)

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

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

ES8 - Trailing Commas

在 ES8 中,我们允许在函数定义和调用时多加一个逗号:

function foo(m, n,) {};
foo(20, 30,);

ES8 - Object Descriptors

ES8 中增加了另一个对对象的操作是 Object.getOwnPropertyDescriptors ,这个在之前已经讲过了,这里不再重 复

ES9 新增知识点

  • Async iterators:后续迭代器讲解
  • Object spread operators:前面讲过了
  • Promise finally:后续讲 Promise 讲解

ES10 - flat flatMap

  • flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返 回。
const nums = [
  10,
  20,
  [2, 9],
  [
    [30, 40],
    [10, 45],
  ],
  78,
  [55, 88],
]
const newNums = nums.flat()
console.log(newNums) // [10,20,2,9,[30,40],[10,45],78,55,88]

const newNums2 = nums.flat(2)
console.log(newNums2) // [10, 20, 2, 9, 30, 40, 10, 45, 78, 55, 88]
  • flatMap() 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。
    • 注意一:flatMap 是先进行 map 操作,再做 flat 的操作;
    • 注意二:flatMap 中的 flat 相当于深度为 1;
const nums2 = [10, 20, 30]
const newNums3 = nums2.flatMap((item) => {
  return item * 2
})
const newNums4 = nums2.map((item) => {
  return item * 2
})

console.log(newNums3) // [20, 40, 60]
console.log(newNums4) // [20, 40, 60]
// flatMap的应用场景
const messages = ['Hello World', 'hello lyh', 'my name is coderwhy']
const words = messages.flatMap((item) => {
  return item.split(' ')
})

console.log(words) // ['Hello', 'World', 'hello', 'lyh', 'my', 'name', 'is', 'coderwhy']

ES10 - Object fromEntries

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

const obj = {
  name: 'why',
  age: 18,
  height: 1.88,
}

const entries = Object.entries(obj)
console.log(entries)

const newObj = {}
for (const entry of entries) {
  newObj[entry[0]] = entry[1]
}

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

const newObj = Object.fromEntries(entries)
console.log(newObj)

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

const queryString = 'name=why&age=18&height=1.88'
const queryParams = new URLSearchParams(queryString)
for (const param of queryParams) {
  console.log(param)
}

const paramObj = Object.fromEntries(queryParams)
console.log(paramObj) // {name: 'why', age: '18', height: '1.88'}

ES10 - trimStart trimEnd

去除一个字符串首尾的空格,我们可以通过 trim 方法,如果单独去除前面或者后面呢? ES10 中给我们提供了 trimStart 和 trimEnd;

const message = '    Hello World    '

console.log(message.trim())
console.log(message.trimStart())
console.log(message.trimEnd())

ES10 其他知识点

  • Symbol description:已经讲过了
  • Optional catch binding:后面讲解 try cach 讲解

ES11 - BigInt

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

// ES11之前 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) // 900719925474099110n

// Number 转 BigInt
const num = 100
console.log(bigInt + BigInt(num)) // 900719925474099200n

// BigInt 转 Number
const smallNum = Number(bigInt)
console.log(smallNum) // 900719925474099100

ES11 - Nullish Coalescing Operator

ES11,Nullish Coalescing Operator 增加了空值合并操作符:

const foo = undefined
// const bar = foo || "default value";
const bar = foo ?? 'defualt value'

console.log(bar) // default value

ES11 - Optional Chaining

可选链也是 ES11 中新增一个特性,主要作用是让我们的代码在进行 null 和 undefined 判断时更加清晰和简洁:

const info = {
  name: 'why',
  // friend: {
  //   girlFriend: {
  //     name: "hmm"
  //   }
  // }
}

if (info && info.friend && info.friend.girlFriend) {
  console.log(info.friend.girlFriend.name)
}

// ES11提供了可选链(Optional Chainling)
console.log(info.friend?.girlFriend?.name) // undefined

ES11 - Global This

在之前我们希望获取 JavaScript 环境的全局对象,不同的环境获取的方式是不一样的; 比如在浏览器中可以通过 this、window 来获取;比如在 Node 中我们需要通过 global 来获取;

那么在 ES11 中对获取全局对象进行了统一的规范:globalThis

// 获取某一个环境下的全局对象(Global Object)

// 在浏览器下
// console.log(window)
// console.log(this)

// 在node下
// console.log(global)

// ES11
console.log(globalThis)

ES11 - for..in 标准化

在 ES11 之前,虽然很多浏览器支持 for...in 来遍历对象类型,但是并没有被 ECMA 标准化。在 ES11 中,对其进行了标准化,for...in 是用于遍历对象的 key 的:

const obj = {
  name: 'why',
  age: 18,
}

for (const item in obj) {
  console.log(item)
}

ES11 其他知识点

  • Dynamic Import:后续 ES Module 模块化中讲解。
  • Promise.allSettled:后续讲 Promise 的时候讲解。
  • import meta:后续 ES Module 模块化中讲解。

ES12 - FinalizationRegistry

FinalizationRegistry 对象可以让你在对象被垃圾回收时请求一个回调。FinalizationRegistry 提供了这样的一种方法:当一个在注册表中注册的对象被回收时,请求在某个时间点上调用一个清理回调。(清理回调有时被称为 finalizer ); 你可以通过调用 register 方法,注册任何你想要清理回调的对象,传入该对象和所含的值;

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

let obj = { name: 'why' }
let info = { age: 18 }

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

obj = null
info = null

// 垃圾回收时,打印如下
// 注册在finalRegistry的对象, 某一个被销毁 value
// VM1565:2 注册在finalRegistry的对象, 某一个被销毁 obj

ES12 - WeakRefs

如果我们默认将一个对象赋值给另外一个引用,那么这个引用是一个强引用:如果我们希望是一个弱引用的话,可以使用 WeakRef;

// ES12: WeakRef类
// WeakRef.prototype.deref:
// > 如果原对象没有销毁, 那么可以获取到原对象
// > 如果原对象已经销毁, 那么获取到的是undefined
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()?.name)
  console.log(info.deref() && info.deref().name)
}, 10000)

// 打印如下
// 注册在finalRegistry的对象, 某一个被销毁 obj
// undefined
// undefined

ES12 - logical assignment operators

// 1.||= 逻辑或赋值运算
let message = ''
// message = message || "default value";
message ||= 'default value'
console.log(message) // default value
// 2.&&= 逻辑与赋值运算
// &&
const obj = {
  name: 'why',
  foo: function () {
    console.log('foo函数被调用')
  },
}

obj.foo && obj.foo()

// &&=
let info = {
  name: 'why',
}

// 1.判断info
// 2.有值的情况下, 取出info.name
// info = info && info.name
info &&= info.name
console.log(info) // why
// 3.??= 逻辑空赋值运算
let message = 0
message ??= 'default value'
console.log(message) // 0

let foo = null // undefined 或者 null 时,会取默认值,其它情况取原来的值
foo ??= 'default value'
console.log(foo) // default value

ES12 其他知识点

  • Numeric Separator:讲过了;
  • String.replaceAll:字符串替换;

replaceAll() 方法返回一个新字符串,新字符串所有满足 pattern 的部分都已被 replacement 替换。pattern 可以是一个字符串或一个 RegExp, replacement 可以是一个字符串或一个在每次匹配被调用的函数。

const p = 'dog dog'

console.log(p.replaceAll('dog', 'monkey')) // monkey monkey
console.log(p.replace(/dog/g, 'monkey')) // monkey monkey

目录