ES2020(ES11)

新特性:

  • String.prototype.matchAll
  • import()
  • import.meta
  • BigInt – 任意精度整数
  • Promise.allSettled
  • globalThis
  • for-in
  • 可选链 — ?.
  • 空值合并运算符 — ??
  • export * as ns from "mod"

String.prototype.matchAll()

matchAll() 返回全局正则表达式的所有匹配项。

给定一个字符串或一个正则表达式,matchAll() 在所有匹配项的匹配对象上返回一个可迭代对象。

let regexp = /t(e)(st(\d?))/
let str = 'test1test2'

// 使用扩展运算符 `(...)` 将可迭代对象转换为数组:
let array = [...str.matchAll(regexp)]

array[0] // ["test1", "e", "st1", "1"]
array[1] // ["test2", "e", "st2", "2"]

注意:必须设置 g 修饰符

RegExp.prototype.exec()/g

在以下示例中,我们收集数组匹配中组 1 的所有捕获:

function collectGroup1(regExp, str) {
  const matches = []
  while (true) {
    const match = regExp.exec(str)
    if (match === null) break
    // 将组 1 的捕获添加到 matches
    matches.push(match[1])
  }
  return matches
}

collectGroup1(/"([^"]*)"/ug, `"foo" and "bar" and "baz"`) // [ 'foo', 'bar', 'baz' ]

没有标志 /gexec() 始终只返回第一个匹配项:

const re = /[abc]/
re.exec('abc') // [ 'a', index: 0, input: 'abc' ]

re.exec('abc') // [ 'a', index: 0, input: 'abc' ]

这对 collectGroup1() 来说是个坏消息,因为如果 regExp 没有标志 /g,它将永远不会完成。

String.prototype.match()/g

如果你使用 match(),使用设置了标志 /g 的正则表达式,可以在一个数组中获得它的所有完整匹配项(换句话说,捕获组被忽略):

'abab'.match(/a/ug) // [ 'a', 'a' ]

如果未设置 /gmatch() 的工作原理与 RegExp.prototype.exec() 类似:

'abab'.match(/a/u) // [ 'a', index: 0, input: 'abab' ]

String.prototype.replace()/g

你可以使用一个技巧通过收集捕获 replace():我们使用一个函数来计算替换值。该函数接收所有捕获信息。但是,它不计算替换值,而是在数组匹配中收集感兴趣的数据:

function collectGroup1(regExp, str) {
  const matches = []
  function replacementFunc(all, first) {
    matches.push(first)
  }
  str.replace(regExp, replacementFunc)
  return matches
}

collectGroup1(/"([^"]*)"/ug, `"foo" and "bar" and "baz"`) // [ 'foo', 'bar', 'baz' ]

对于不带标志 /g 的正则表达式,replace() 只访问第一个匹配项。

RegExp.prototype.test()

test() 只要正则表达式匹配,就返回 true

const regExp = /a/ug
const str = 'aa'

regExp.test(str) // true
regExp.test(str) // true
regExp.test(str) // false

String.prototype.split()

split() 可以拆分字符串并使用字符串或正则表达式指定分隔符。如果该正则表达式至少包含一个捕获组,则 split() 返回一个数组,其中子字符串与第一个组捕获的内容交错:

const regExp = /<(-+)>/ug
const str = 'a<--->b<->c'

str.split(regExp) // [ 'a', '---', 'b', '-', 'c' ]

动态导入 import()

在此之前,我们只能使用静态导入,它只接受模块路径的字符串。使用动态导入,我们必须使用 Promise 有条件地导入模块。

<nav>
  <a href="books.html" data-entry-module="books">Books</a>
  <a href="movies.html" data-entry-module="movies">Movies</a>
  <a href="video-games.html" data-entry-module="video-games">Video Games</a>
</nav>

<main>Content will load here!</main>
const main = document.querySelector('main')
for (const link of document.querySelectorAll('nav > a')) {
  link.addEventListener('click', (e) => {
    e.preventDefault()

    import(`./section-modules/${link.dataset.entryModule}.js`)
      .then((module) => {
        module.loadPageInto(main)
      })
      .catch((err) => {
        main.textContent = err.message
      })
  })
}

点击此处👉 Loading modules dynamically via import() 了解更多内容。

import.meta

用于保存有关当前模块的特定于主机的元数据的元属性

(async () => {
  const response = await fetch(new URL("../hamsters.jpg", import.meta.url))
  const blob = await response.blob()

  const size = import.meta.scriptElement.dataset.size || 300

  const image = new Image()
  image.src = URL.createObjectURL(blob)
  image.width = image.height = size

  document.body.appendChild(image)
})()

点击此处👉 import.meta – metadata for the current module 了解更多内容。

BigInt — 任意精度整数

BigInt 一种用于大整数运算的新原始数据类型,表示大于 2⁵³ 的数字。

BigInt 使用一系列数字,后缀为 n

const theBiggestInt = 9886881870000166n

const alsoHuge = BigInt(9886881870000166) // 9007199254740991n

const hugeButString = BigInt('9886881870000166') // 9886881870000166n

typeof 的返回值为 bigint

typeof 123n // 'bigint'

Promise.allSettled()

当所有给定的 Promise 都得到解决时返回(resolvedrejected,无关紧要)。

const sleep = sm => new Promise(resolve => setTimeout(() => resolve(sm), sm))
const err = (ms) => sleep(ms).then(() => Promise.reject(ms))

Promise.allSettled([1, 2, 3]).then(console.log)
Promise.allSettled([sleep(300), sleep(100), sleep(200)]).then(console.log)
Promise.allSettled([sleep(3000), err(100), sleep(2000)]).then(console.log)
Promise.allSettled([err(50), err(60)]).then(console.log)

globalThis

在此之前,全局对象由于不同的 JavaScript 环境有不同的语法:

  • 在 Web 浏览器可以是 windowselfframesthis
  • 对于 Web Worker 来说,它是 self
  • 在 Node.js 中,它是 global

globalThis 为所有 JavaScript 环境中的全局对象提供了单一语法。

// node 环境
console.log(globalThis)

/**
<ref *1> Object [global] {
  global: [Circular *1],
  clearInterval: [Function: clearInterval],
  clearTimeout: [Function: clearTimeout],
  setInterval: [Function: setInterval],
  setTimeout: [Function: setTimeout] {
    [Symbol(nodejs.util.promisify.custom)]: [Function (anonymous)]
  },
  queueMicrotask: [Function: queueMicrotask],
  clearImmediate: [Function: clearImmediate],
  setImmediate: [Function: setImmediate] {
    [Symbol(nodejs.util.promisify.custom)]: [Function (anonymous)]
  }
}
*/

// 浏览器
globalThis // Window {0: global, 1: global, window: Window, self: Window, …}

注意:globalThis 并不总是直接指向全局对象。详细可查阅 In browsers, globalThis does not point directly to the global object

globalThis 会对性能产生负面影响,也可能会产生一些不到的错误,建议使用 ES6 的一些特性避免全局对象,例如:

  • 声明在 constletclass 全局作用域内,使用时不会创建全局对象属性。
  • 每个 ES 模块都有自己的局部作用域。(默认开启严格模式)

可选链 — ?.

可选链 ?. 是一种访问嵌套对象属性的安全的方式。即使中间的属性不存在,也不会出现错误。

如果问号前面的值不是 undefined 也不是 null,则执行问号后面的操作。否则,返回 undefined。它有如下三种语法:

obj?.prop       // 可选的静态属性访问
obj?.[prop]     // 可选的动态属性访问
func?.(...args) // 可选方法调用
  • obj?.prop — 如果 obj 存在则返回 obj.prop,否则返回 undefined
  • obj?.[prop] — 如果 obj 存在则返回 obj[prop],否则返回 undefined
  • obj.method?.(...args) — 如果 obj.method 存在则调用 obj.method(),否则返回 undefined
const user = {}

user.address.street // TypeError
user?.address?.street // undefined

可选链的替代方案

&&
user && user.address && user.address.street // undefined

缺点:

  • 语法冗长
  • 如果失败,&&返回其左侧,而 ?. 始终返回 undefined
  • && 对所有虚值的左侧都失败,而 ?. 只对undefinednull 失败:
解构

您还可以使用解构来处理链式属性访问,但这并不美观:

const { address: { street = undefined } = {} } = user

street // undefined
第三方库:Lodash 库的 get() 方法
_.get(user, 'address.street')

支持情况

可选链(?.)已经支持大部分的主流浏览器:

可选链

如果您需要支持 IE 或更低版本浏览器,babel 有一个插件 — @babel/plugin-proposal-optional-chaining

点击此处👉 可选链 "?." 了解更多内容。

空值合并运算符 — ??

?? 为二元运算符。如果左侧表达式的值为 nullundefined,则计算运算符的右侧。

const data = {
  nullValue: null,
  height: 400,
  animationDuration: 0,
  headerText: '',
  showSplashScreen: false
}

console.log(data.undefinedValue ?? 'some other default') // 'some other default'
console.log(data.nullValue ?? 'some other default') // 'some other default'
console.log(data.headerText ?? 'Hello, world!') // ''
console.log(data.animationDuration ?? 300) // 0
console.log(data.showSplashScreen ?? true) // false

可以看到,它只关心左侧的值是否为 nullundefined,而不在乎是否为虚值。

点击此处👉 空值合并运算符 '??' 了解更多内容。

export * as ns from 'mod'

语法:

export * as ns from 'module'

示例:

export * as ns from './utils'

// 👆 等同于 👇

import * as ns from './utils'
export { ns }

扩展

Airbnb 规范建议我们不要使用通配符导入。

原因:确保您有一个默认导出。

// bad
import * as AirbnbStyleGuide from './AirbnbStyleGuide'

// good
import AirbnbStyleGuide from './AirbnbStyleGuide'

并且不要直接从 importexport

原因:尽管单行代码很简洁,但是使用一种清晰的导入方式和一种清晰的导出方式可以使事情保持一致。

// bad
// es6.js
export { es6 as default } from './AirbnbStyleGuide'

// good
// es6.js
import { es6 } from './AirbnbStyleGuide'
export default es6

点击此处👉Normative: Add export * as ns from "mod” to Export production and Module Semantic 了解更多详情。

指定 for-in 枚举顺序

不同的引擎已就如何指定 for-in 枚举顺序达成一致,从而使行为标准化。

let obj = {
  p1: 'p1',
  p2: 'p2',
  p3: 'p3'
}

let keys = []
for (let key in o) {
  if (key === 'p1') {
    o.p4 = 'p4'
  }
  keys.push(key)
}

更多资料

ECMAScript 2020: the final feature set

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值