# 前言声明

  • 本章大量释义来源于 MDN

# ES7

# includes

  • 在 ES7 之前,如果我们想判断一个数组中是否包含某个元素,需要通过 indexOf 获取结果,并且判断是否为 -1。
  • 在 ES7 中,我们可以通过 includes 来判断一个数组中是否包含一个指定的元素,根据情况,如果包含则返回 true,否则返回 false。
const friends = ['伊莉雅', '樱岛麻衣', '入间同学', '薇尔莉特', NaN]
// 在判断 +0 与 -0 时,被认为是相同的。
[1, 2, 3, +0].indexOf(-0)    // 3
[1, 2, 3, +0].includes(-0)  // true
// 这里可以看出数组是包含 NaN 的 indexOf 返回的却是 -1
friends.indexOf('樱岛麻衣') // 1
friends.indexOf('saber') // -1
friends.includes('伊莉雅') // true
friends.includes('saber') // false
// 只能判断简单类型的数据,对于复杂类型的数据,比如对象类型的数组,二维数组,这些,是无法判断的.
const arr = [[1, 2], 3]
arr.includes([1, 2]);  //false
arr.indexOf([1, 2]);   //-1
  • includes & indexof 区别
const friends = ['伊莉雅', '樱岛麻衣', '入间同学', '薇尔莉特', NaN]
// 这里可以看出数组是包含 NaN 的 indexOf 返回的却是 -1  includes 则是 true
friends.indexOf(NaN) // -1
friends.includes(NaN) // true
// 第二个参数为 2 代表从第 2 个元素之后开始判断
friends.includes('樱岛麻衣', 2) // false

# 指数运算符

  • 在 ES7 之前,计算数字的乘方需要通过 Math.pow 方法来完成。
  • 在 ES7 中,增加了 ** 运算符,可以对数字来计算乘方
const result1 = Math.pow(2, 5) 
const result2 = 2 ** 5 
console.log(result1) // 32
console.log(result2) // 32

# ES8

# Object.values

  • Object.values() 返回一个数组,其元素是在对象上找到的可枚举属性值。属性的顺序与通过手动循环对象的属性值所给出的顺序相同。
const lain = {
  name: 'lain',
  age: 16
}
// 传入对象
Object.values(lain) //  ['lain', 16]
// 传入数组
['樱岛麻衣', '薇尔莉特', '伊莉雅']) //  [' 樱岛麻衣 ', ' 薇尔莉特 ', ' 伊莉雅 ']
// 传入字符串
Object.values('樱岛麻衣是我老婆') //  [' 樱 ', ' 岛 ', ' 麻 ', ' 衣 ', ' 是 ', ' 我 ', ' 老 ', ' 婆 ']

# Object.entries

  • Object.entries() 返回一个数组,其元素是与直接在 object 上找到的可枚举属性键值对相对应的数组。属性的顺序与通过手动循环对象的属性值所给出的顺序相同。
const lain = {
  name: 'lain',
  age: 16
}
// 传入对象
Object.entries(lain) // [ [ 'name', 'lain' ], [ 'age', 16 ] ]
// 传入数组
Object.entries(['樱岛麻衣', '薇尔莉特', '伊莉雅']) // [['0', ' 樱岛麻衣 '], [ '1', ' 薇尔莉特 ' ], [ '2', ' 伊莉雅 ' ] ]
// 传入字符串
Object.entries('樱岛麻衣') // [['0', ' 樱 '], [ '1', ' 岛 ' ], [ '2', ' 麻 ' ], [ '3', ' 衣 ' ] ]

# padStart

  • padStart() 方法用另一个字符串填充当前字符串 (如果需要的话,会重复多次),以便产生的字符串达到给定的长度。从当前字符串的左侧开始填充。
  • 语法: str.padStart(targetLength [, padString])
  • 参数:
    • targetLength: 当前字符串需要填充到的目标长度。如果这个数值小于当前字符串的长度,则返回当前字符串本身。
    • padString 可选 填充字符串。如果字符串太长,使填充后的字符串长度超过了目标长度,则只保留最左侧的部分,其他部分会被截断。此参数的默认值为 " "(U+0020)。
  • 返回值: 在原字符串开头填充指定的填充字符串直到目标长度所形成的新字符串。
const str = '樱岛麻衣'
str.padStart(8)      //     樱岛麻衣
str.padStart(8, '-') //---- 樱岛麻衣

# padEnd

  • padEnd() 方法会用一个字符串填充当前字符串(如果需要的话则重复填充),返回填充后达到指定长度的字符串。从当前字符串的末尾(右侧)开始填充。
  • 语法: str.padEnd(targetLength [, padString])
  • 参数:
    • targetLength: 当前字符串需要填充到的目标长度。如果这个数值小于当前字符串的长度,则返回当前字符串本身。
    • padString 可选 填充字符串。如果字符串太长,使填充后的字符串长度超过了目标长度,则只保留最左侧的部分,其他部分会被截断。此参数的缺省值为 " "(U+0020)。
  • 返回值:在原字符串末尾填充指定的填充字符串直到目标长度所形成的新字符串。
const str = '樱岛麻衣'
str.padEnd(1)         // 樱岛麻衣  
str.padEnd(10)        // 樱岛麻衣 empty*6     
str.padEnd(10, "*")   // 樱岛麻衣 ******
str.padEnd(8, "-")    // 樱岛麻衣 ----

# Demo

const identityCard = '421126200006132333'
const lastIdentityCard = identityCard.slice(-4)
lastIdentityCard.padStart(identityCard.length, '*') // **************2333

# ES10

# flat

  • flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。
  • 语法: var newArray = arr.flat([depth])
  • 参数:
    • depth 可选 指定要提取嵌套数组的结构深度,默认值为 1
  • 返回值:一个包含将数组与子数组中所有元素的新数组。
// 声明一个多维数组
const arr = [1, 2, 3, [4, 5], [6, 7, [8, 9], [10, [11, 12]]]]
// 数组降维默认为 1
arr.flat() // [ 1, 2, 3, 4, 5, 6, 7, [ 8, 9 ], [ 10, [ 11, 12 ] ] ]
// 数组降维 2
arr.flat(2) // [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, [ 11, 12 ] ]
// 使用 Infinity,可展开任意深度的嵌套数组
arr.flat(Infinity) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

# flagMap

  • flatMap() 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与 map 连着深度值为 1 的 flat 几乎相同,但 flatMap 通常在合并成一种方法的效率稍微高一些。

  • 语法: var new_array = arr.flatMap(function callback(currentValue[, index[, array]]) { // return element for new_array }[, thisArg])

  • 参数:

    • callback 可以生成一个新数组中的元素的函数,可以传入三个参数:

    • currentValue 当前正在数组中处理的元素

    • index 可选 可选的。数组中正在处理的当前元素的索引。

    • array 可选 可选的。被调用的 map 数组

    • thisArg 可选 可选的。执行 callback 函数时 使用的 this 值。

  • flatMap 方法与 map 方法和深度 depth 为 1 的 flat 几乎相同.

const characters = ['薇尔莉特 小鸟游六花','稚名真白 土间埋']
// 使用 map 得到的是多维数组
const words1 = characters.map(item => item.split(' '))
console.log(words1) // [[' 薇尔莉特 ', ' 小鸟游六花 '], [ ' 稚名真白 ', ' 土间埋 ' ] ]
// 使用 flatMap 得到的是一维数组
const words2 = characters.flatMap(item => item.split(' '))
console.log(words2) // [' 薇尔莉特 ', ' 小鸟游六花 ', ' 稚名真白 ', ' 土间埋 ']

# Object.fromEntries

  • Object.fromEntries() 方法把键值对列表转换为一个对象。、
  • 语法: Object.fromEntries(iterable)
  • 参数: iterable 类似 Array Map 或者其它实现了可迭代协议的可迭代对象。
  • 返回值:一个由该迭代对象条目提供对应属性的新对象。
  • Object.fromEntries() 方法接收一个键值对的列表参数,并返回一个带有这些键值对的新对象。这个迭代参数应该是一个能够实现 @@iterator 方法的的对象,返回一个迭代器对象。它生成一个具有两个元素的类数组的对象,第一个元素是将用作属性键的值,第二个元素是与该属性键关联的值。
  • Object.fromEntries() 执行与 Object.entries 互逆的操作。
const entries = new Map([
  ['lain', 16],
  ['saber', 17]
])
console.log(entries) // Map(2) { 'lain' => 16, 'saber' => 17 }
const fromEntries = Object.fromEntries(entries)
console.log(fromEntries) // { lain: 16, saber: 17 }

# Demo

const queryString = 'name=saber&age=16'
const queryParams = new URLSearchParams(queryString)
console.log(queryParams) // URLSearchParams { 'name' => 'saber', 'age' => '16' }
for (const param of queryParams) {
  console.log(param) // [ 'name', 'saber' ]  [ 'age', '16' ]
}
// 使用 Object.fromEntries 转换为对象  与 Object.entries 相反
const paramObj = Object.fromEntries(queryParams)
console.log(paramObj) // { name: 'saber', age: '16' }

# trim()

# trimStart()

  • trimStart() 方法从字符串的开头删除空格。 trimLeft() 是此方法的别名。
  • 返回值:一个新字符串,表示从其开头(左端)除去空格的调用字符串。
  • trimStart() / trimLeft() 方法移除原字符串左端的连续空白符并返回一个新字符串,并不会直接修改原字符串本身。
  • 别名:为了与 String.prototype.padStart 等函数保持一致,标准方法名称为 trimStart 。 但是,出于 Web 兼容性原因, trimLeft 仍然是 trimStart 的别名。在某些引擎中,这意味着: String.prototype.trimLeft.name === "trimStart"
const str = '   Hello World'
str.trimStart() // ''*3Hello World

# trimEnd

  • trimEnd() 方法从一个字符串的末端移除空白字符。trimRight () 是这个方法的别名。
  • 返回值:一个新字符串,表示从调用字串的末(右)端除去空白。
  • trimEnd() / trimRight() 方法移除原字符串右端的连续空白符并返回, trimEnd() / trimRight() 方法并不会直接修改原字符串本身。
  • 别名:为了与 String.prototype.padEnd 等函数保持一致,标准方法名称为 trimEnd 。 但是,出于 Web 兼容性原因, trimRight 仍然是 trimEnd 的别名。 在某些引擎中,这意味着: String.prototype.trimRight.name === "trimEnd";
const str = 'Hello World   '
str.trimEnd()   // Hello World''*3

# description

  • description 是一个只读属性,它会返回 Symbol 对象的可选描述的字符串。
  • 语法: Symbol('myDescription').description;Symbol.iterator.description;Symbol.for('foo').description;
  • Symbol 对象可以通过一个可选的描述创建,可用于调试,但不能用于访问 symbol 本身。
Symbol('lain').description // lain
Symbol('').description // ''
Symbol().description // undefined
Symbol([1, 2, '3']).description // 1,2,3
Symbol({name: 'lain'}).description // [object Object]

# ES11

# BigInt

  • BigInt 是一种内置对象,它提供了一种方法来表示大于 253 - 1 的整数。这原本是 Javascript 中可以用 Number 表示的最大数字。 BigInt 可以表示任意大的整数。
BigInt(2 ** 53 - 1) // 9007199254740991n
  • 可以用在一个整数字面量后面加 n 的方式定义一个 BigInt ,如: 10n ,或者调用函数 BigInt()
const bigInt = BigInt(10)
console.log(typeof bigInt)
console.log(bigInt + 10n) // 20n
const num1 = 100
const num2 = 100
console.log(bigInt + BigInt(num1)) // 110n
console.log(bigInt + BigInt(num2)) // 110n
  • 将 BigInt 转成 Number 类型
const bigInt = BigInt(10)
// 如果将大数转成 Number 类型,不一定能安全表示
const smallNum = Number(bigInt)
console.log(smallNum) // 10

# Nullish coalescing operator

  • 空值合并操作符 ?? )是一个逻辑操作符,当左侧的操作数为 null 或者 undefined 时,返回其右侧操作数,否则返回左侧操作数。
  • 逻辑或操作符( ||不同,逻辑或操作符会在左侧操作数为假值时返回右侧操作数。也就是说,如果使用 || 来为某些变量设置默认值,可能会遇到意料之外的行为。比如为假值(例如, ''0 )时。见下面的例子。
const nullValue = null;
const emptyText = ""; 
const someNumber = 233;
const valA = nullValue ?? "default valA" // "efault valA"
const valB = emptyText ?? "default valB" // "default valB"
const valC = someNumber ?? 0 // 233
const valD = null ?? 'null value' // null value
const valE = undefined ?? 'undefined value' // 'undefined value'

# Optional Chaining

  • 可选链操作符 ( ?. ) 允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。 ?. 操作符的功能类似于 . 链式操作符,不同之处在于,在引用为空 (nullish ) ( null 或者 undefined ) 的情况下不会引起错误,该表达式短路返回值是 undefined 。与函数调用一起使用时,如果给定的函数不存在,则返回 undefined
  • 当尝试访问可能不存在的对象属性时,可选链操作符将会使表达式更短、更简明。在探索一个对象的内容时,如果不能确定哪些属性必定存在,可选链操作符也是很有帮助的。
const lain = {
  name: 'lain',
}
console.log(lain.friend?.name) // undefined

# globalThis

  • 全局属性 globalThis 包含全局的 this 值,类似于全局对象(global object)
console.log(globalThis) // Browser -> window
  • 详情请参考 MDN

# ES12

# FinalizationRegistry

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

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

  • GC (Garbage Collection) 会不定时回收, 并不是立即销毁就回收的。

    const finalRegistry = new FinalizationRegistry((heldValue ) => {
      console.log(`注册在finalRegistry中的 ${heldValue} 对象被销毁了`)
    })
    let lain = {
      name: 'lain'
    }
    let saber = {
      name: 'saber'
    }
    finalRegistry.register(lain, 'lain')
    finalRegistry.register(saber, 'saber')
    console.log(finalRegistry)
    lain = null
    saber = null

# WeakRef

WeakRef 对象允许您保留对另一个对象的弱引用,而不会阻止被弱引用对象被 GC 回收

WeakRef.prototype.deref() 返回当前实例的 WeakRef 对象所绑定的 target 对象,如果该 target 对象已被 GC 回收则返回 undefined

  • 详情请参考 MDN
const finalRegistry = new FinalizationRegistry((heldValue ) => {
  console.log(`注册在finalRegistry中的 ${heldValue} 对象被销毁了`)
})
let lain = {
  name: 'lain'
}
let newLain = new WeakRef(lain)
finalRegistry.register(lain, 'lain')
finalRegistry.register(newLain, 'newLain')
console.log(finalRegistry)
lain = null
setTimeout(() => {
  console.log(newLain.deref()?.name) // lain
}, 10000) // GC 回收了 lain 后 获取到的则是 undefined

# logical-assign-operator

# ||=

  • 逻辑或赋值( x ||= y )运算仅在 x值时赋值。
const example = {
  a: 1,
  b: 0,
  c: '',
  d: null,
  e: undefined
}
example.a ||= 'default value' // 1
example.b ||= 'default value' // default value
example.c ||= 'default value' // default value
example.d ||= 'default value' // default value
example.e ||= 'default value' // default value

# &&=

  • 逻辑和赋值 (x &&= y) 操作符只在 x 为真时才赋值。
  • 空值合并运算符从左至右求值,其使用以下规则测试是否可能进行语法短路求值: (结果非 null 或 undefined 的表达式) ?? expr 被短路求值为左侧表达式,当左侧证明为既非 null 也非 undefined .
const example = {
  a: 1,
  b: 0,
  c: '',
  d: null,
  e: undefined
}
example.a &&= 'default value' // default value
example.b &&= 'default value' // 0
example.c &&= 'default value' // ''
example.d &&= 'default value' // null
example.e &&= 'default value' // undefined

# ??=

  • 逻辑空赋值运算符 ( x ??= y ) 仅在 xnullish ( nullundefined ) 时对其赋值。
const example = {
  a: 1,
  b: 0,
  c: '',
  d: null,
  e: undefined
}
example.a ??= 'default value' // 1
example.b ??= 'default value' // 0
example.c ??= 'default value' // ''
example.d ??= 'default value' // default value
example.e ??= 'default value' // default value

# numeric separator

const num = 1_000_000
console.log(num) // 1000000

# replaceAll

### const str = 'Hello World'
console.log(str.replaceAll('o', 'a')) // Hella Warld
console.log(str) // 'Hello World'