JS Advance --- ES6 ~ ES12语法 (四)

1,336 阅读7分钟

获取对象的键值对

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

const user = {
  name: 'Klaus',
  age: 23
}

// 以下三个方法的参数类型 是 可迭代对象
console.log(Object.keys(user)) // => [ 'name', 'age' ]
console.log(Object.values(user)) // => [ 'Klaus', 23 ]

// entry --> [key, value]
// entries --> [[key, value], [key, value]]
console.log(Object.entries(user)) // => [ [ 'name', 'Klaus' ], [ 'age', 23 ] ]


const friends = ['Alex', 'Klaus', 'Steven']
console.log(Object.keys(friends)) // => [ '0', '1', '2' ]
console.log(Object.values(friends)) // => [ 'Alex', 'Klaus', 'Steven' ]
console.log(Object.entries(friends)) // => [ [ '0', 'Alex' ], [ '1', 'Klaus' ], [ '2', 'Steven' ] ]

const str = 'Alex'
console.log(Object.keys(str)) // => [ '0', '1', '2', '3' ]
console.log(Object.values(str)) // => [ 'A', 'l', 'e', 'x' ]
console.log(Object.entries(str)) // => [ [ '0', 'A' ], [ '1', 'l' ], [ '2', 'e' ], [ '3', 'x' ] ]

String Padding

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

const str = 'Hello World'

// padStart(字符串前填充), padEnd(字符串后填充)
// 参数1 ---> 填充后字符串的总长
// 参数2 ---> 填充的内容 (默认为空格)
console.log(str.padStart(15, '*')) // => ****Hello World
console.log(str.padEnd(15, '-')) // => Hello World----
const str = 'Hello World'

// 如果填充后,字符串总长比原来的字符串短
// 那么填充后字符串的长度等于原本字符串的长度
// 此时填充失效
console.log(str.padStart(5, '*')) // => Hello World
console.log(str.padEnd(5, '-')) // => Hello World

Trailing Commas

// ES5前,在函数的实参或形参的最后是不可以加上一个多余的逗号的
// 但是ES8开始, 函数的实参或形参的最后加上一个多余的逗号,JS引擎可以正常识别并进行解析
function fun(a, b,) {

}

fun(a, b,)

Object spread operator

const obj = {
  name: 'Klaus',
  age: 23
}

console.log({...obj}) // => { name: 'Klaus', age: 23 }
console.log({...obj} === obj) // => false

扁平化

flat

flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返 回。

const arr = ['key', 'value', ['Hello', 'World'], [['name', 'Klaus'], ['age', 18]]]

// flat参数为需要降几维 --- 默认值为1
// 如果维度超过了可以扁平化处理的最大维度 --- 就按照最大可以扁平化的维度进行处理
console.log(arr.flat())
/*
  =>
    [
      'key',
      'value',
      'Hello',
      'World',
      [ 'name', 'Klaus' ],
      [ 'age', 18 ]
    ]
*/

console.log(arr.flat(2))
/*
  =>
    [
      'key',   'value',
      'Hello', 'World',
      'name',  'Klaus',
      'age',   18
    ]
*/

flatMap

flatMap() 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。

  • flatMap是先进行map操作,再做flat的操作
  • flatMap中的flat相当于深度为1 ---> 也就是flatMap只能进行维度为1的扁平化操作,而且不可以手动指定扁平化的维度
const message = ['Hello World', 'Hello Message', 'Hello React']

// console.log(message.map(item => item.split(' ')).flat())
// 等价于
console.log(message.flatMap(item => item.split(' ')))

fromEntries

const user = {
  name: 'Klaus',
  age: 18
}

// fromEntries 是 entries 的逆操作
const entries = Object.entries(user)
console.log(Object.fromEntries(entries)) // => { name: 'Klaus', age: 18 }
const str = 'name=klaus&age=23&height=18'

// new URLSearchParams(queryString) 返回的结果是一个entries对象
const params = new URLSearchParams(str)

for (const entry of params) {
  console.log(entry)
}

console.log(Object.fromEntries(params)) // => { name: 'klaus', age: '23', height: '18' }

去除空格

const str = '   Hello World   '

console.log(str.trim()) // => 'Hello World'
console.log(str.trimStart()) // => 'Hello World   '
console.log(str.trimEnd()) // => '   Hello World'

BigInt

在早期的JavaScript中,我们不一定能正确的表示过大的数字

// 获取可以表示的最大整数
console.log(Number.MAX_SAFE_INTEGER)

在ES11中,引入了新的数据类型BigInt,用于表示过大的整数

// BigInt的表示方法是在数值的后面加上n
const bigInt = 9007199254740991n

// 注意: BigInt不可以和普通的Number类型混用(别的数据类型可以)
// console.log(bigInt + 11) // => error
// console.log(bigInt + 11.5) // => error
console.log(bigInt + 'ww') // => 9007199254740991ww

// BigInt在输出值的时候,会在最后加上n,以做区分
console.log(bigInt + 11n) // => 9007199254741002n

// BigInt方法可以将普通数值类型转换为BigInt类型
// BigInt方法的参数只能是整数类型的数值或对应的字符串
// 即使是浮点类型的Number值,BigInt也无法进行数值类型的转换
console.log(BigInt(22)) // => 22n
console.log(BigInt('22')) // => 22n

// console.log(BigInt(12.5)) // => error
// console.log(BigInt('22.5')) // => error
// console.log(BigInt('ww')) // => error

// 可以使用Number方法将BigInt类型的数据转换为普通Number类型
// 但是因为JS无法使用Number表示过大的整数
// 所以并不一定能保证被转换后数值的准确性
console.log(Number(bigInt)) // => 9007199254740991

空值合并运算符

// ES5中表示默认值 常见的方式
console.log(undefined || 'default') // => default
console.log(null || 'default') // => default

// 但是遇到以下情况不应该是默认值的时候,却被判定为默认值
console.log(0 || 'default') // => default
console.log('' || 'default') // => default
console.log(false || 'default') // => default

// 所以,ES5中真正表示默认值的方式为
const foo = 0
const res = [null, undefined].includes(foo) ? 'default' : foo
// 但是这么书写过于麻烦,所以ES11提供了 空值合并运算符(Nullish Coalescing Operator)
console.log(undefined ?? 'default') // => default
console.log(null ?? 'default') // => default

console.log(0 ?? 'default') // => 0
console.log('' ?? 'default') // => ''
console.log(false ?? 'default') // => false

Optional Chaining

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

const obj = {
  name: 'Alex'
}

// 如果?.之前返回的结果没有name属性,直接断链,并返回undefined
console.log(null?.name) // => undefined
console.log(undefined?.name) // => undefined
console.log(0?.name) // => undefined
            
console.log(obj?.name) // => Alex
const users = [
  {
    name: 'Alex'
  }
]

// 可选链运算符同样可以使用在数组元素的取值上
console.log(users?.[0]?.name) // => Alex
console.log(users?.[1]?.name) // => undefined
const Alex = {
  name: 'Alex',
  firend: {
    name: 'Jhon'
  }
}

const Klaus = {
  name: 'Klaus'
}

// 打印出某一个用户的friend属性
function printFriend(user) {
  if (user && user.firend && user.friend.name) {
    console.log(user.firend)
  }
}
const Alex = {
  name: 'Alex',
  firend: {
    name: 'Jhon'
  }
}

const Klaus = {
  name: 'Klaus'
}

function printFriend(user) {
  // 可选链运算符
  console.log(user?.firend?.name)
}
const Alex = {
  name: 'Alex',
  firend: {
    name: 'Jhon'
  }
}

const Klaus = {
  name: 'Klaus'
}

console.log(Klaus?.firend?.name) // => undefined
console.log(Alex?.firend?.name) // => Jhon

globalThis

在ES11之前,在JS的不同运行环境下去获取全部对象,获取到的结果是不一样的

  • 浏览器中可以通过this、window来获取
  • Node中我们通过global来获取

所以在ES11中,提供了globalThis来进行获取,即进行了统一的规范

// 在browser中,返回window
// 在node中,返回 global
console.log(globalThis)

FinalizationRegistry

FinalizationRegistry 对象可以让你在对象被垃圾回收时执行一个回调,这个回调一般被称之为finalizer 方法

FinalizationRegistry 提供了这样的一种方法: 当一个在注册表中注册的对象被回收时,会自动执行FinalizationRegistry中传入的回调函数

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

// PS: 以下案例推荐在浏览器环境进行运行
// 1. 浏览器环境有一个单独的运行JS的进程,在浏览页面的时候一直在执行
// 2. 在node环境中,运行的其实是js脚本,所以在运行JS脚本的时候会开启一个线程进行运行
//    在脚本运行完毕以后,node运行js的进程其实已经关闭了,不方便进行测试

// FinalizationRegistry是一个类
// 参数是一个回调函数,也就是Registry函数,会在被注册的变量被GC销毁的时候被执行
const finalRegistry = new FinalizationRegistry(val => console.log(`${val}被回收了`))

let user = { name: 'Klaus' }

// 注册需要被监听的变量
// 参数1:需要被监听的变量
// 参数2:该变量在registry中的key值,也就是在被GC销毁时,会在Registry函数被执行的时候,作为参数被传入
finalRegistry.register(user, 'user')

// 将user设置为垃圾对象
user = null

WeakRef

weakRef可以用来手动创建一个弱引用

const user = { name: 'Klaus' }

// 创建对于user所指向变量的弱引用
const ref = new WeakRef(user)

// 在取值时,需要调用deref来获取原始的值,再进行对应的操作
// 1. 如果对应的值并没有被销毁,那么可以正常取出对应的值
// 2. 如果对于的值已经被GC销毁,那么deref方法的返回值就是undefined
console.log(ref.deref()?.name)

逻辑合并运算符

逻辑合并运算符(logical assignment operators) 即为 ||=,&&=,??=

||=

// ES5
let message = undefined
message = message || 'default value'

console.log(message) //  default value
let message = undefined
message ||= 'default value'

console.log(message) //  default value

??=

// 如果是0或者空字符串或false的时候,我们如果使用逻辑或进行判断的时候,会直接触发对应的默认值
// 所以出现了空值合并运算符
let message = 0
message = message ?? 'default value'

console.log(message) //  0
// 对应的在ES12中,提供了空值合并运算符的简化写法
let message = 0
message ??= 'default value'

console.log(message) //  0

&&=

// ES5
let user = {
  name: 'Klaus'
}

user = user && user.name
console.log(user) // => Klaus
// ES6
let user = {
  name: 'Klaus'
}

user &&= user.name
console.log(user) // => Klaus

Numeric Separator

Numeric Separator只是为了方便我们阅读长度比较长的数值

对于具体多少位进行数值的分割并没有严格的要求

只不过通常情况下,我们会使用三位进行一分割

const num = 123_223_222_223_222_333
console.log(num) // => 123223222223222340

const num1 = 12_3223222223_222_333
console.log(num1) // => 123223222223222340

replaceAll

const str = 'Hello World, Hello React'

console.log(str.replace('Hello', 'New')) // => New World, Hello React
console.log(str.replace(/Hello/g, 'New')) // => New World, New React
console.log(str.replaceAll('Hello', 'New')) // => New World, New React