ES2024 新鲜出炉的 JS 特性先睹为快!

00. 论文背景

图片

今年我们翘首以盼的 ES2024(正式版)即将在下个月正式上线啦!如果不出意外的话......

地球人都知道,自从 2015 年 ES6 发布以来,ECMAScript 每年都会增量更新,十年间日新又新。刚刚才刷过 bilibili 春晚,眨眼间,2024 已经丢了大半年。

此时此刻,ES2024 候选版的所有功能已经全员爆料,且均已载入 ES 语言说明书(ECMAScript Language Specification),只要一个月后付梓官宣就欧了。(我参考的是去年六月中旬的官宣时间)

那么,JS 最新版本 ES2024 到底新增了哪些功能呢?我不允许我的粉丝还蒙在鼓里,所以一起来先睹为快吧。

01. Promise 新增静态方法

Promise 新增静态方法对应的 TC39(技术委员会)提案是“Promise.withResolvers()”。

我的个人心证是,Promise.withResolvers() 类似于 Promise.resolve() 或 Promise.reject(),是用于生成一个待定状态 Promise 实例的语法糖。

一般而言,我们使用 Promise 封装异步任务时,会在 new Promise 传递的回调函数内部,至少调用一个 resolve 或 reject“冻态函数”,用来冻结 Promise 实例的私有状态。

举个栗子,Promise 的基本操作如下所示:

const promise = new Promise((resolve, reject) =>
  '喜欢本文' ? resolve('成功点赞') : reject('收藏失败')
)

但是,如果我们尚未知晓业务逻辑的所有细节,我们期望能够抽离“冻态函数”自由封装,那该怎么办呢?

如果你还没有解锁诸如此类的 Promise 新鲜玩法,那就要睁大眼睛看清楚了,接下来就是见证奇迹的时刻!

2024 之前,我们可以通过 作用域提升 来“曲线救国”,举个栗子:

// 作用域提升
let resolve, reject

// 待定状态的 promise
const promise = new Promise((res, rej) => {
  resolve = res
  reject = rej
})

// 外部冻态
'喜欢本文' ? resolve('成功点赞') : reject('收藏失败')

如你所见,我们可以借助顶层作用域的 let 变量来延迟赋值,同时在回调函数外部自由调用 resolve 或 reject

如此一来,我们不必局限在回调函数中封装所有异步任务,爱哪哪调用都问题不大,你就说妙不妙嘛?

更妙的是,2024 之后,为了支持这种更加放飞自我的使用场景,Promise.withResolvers() 应运而生。

举个栗子,我们可以使用 Promise.withResolvers() 来重构上述功能:

// 一步生成实例和冻态函数
const { promise, resolve, reject } = Promise.withResolvers()

如你所见,一步到位!没有什么是一行代码不能搞定的,这就是“后 ES6 时代”优雅的现代化 JS 代码!

我们不必借助 let 变量“曲线救国”,也不必嵌套一层多余且丑陋的回调函数,重构后的精简代码我直呼绝绝子!

02. String.prototype 新增原型方法

String.prototype 新增原型方法对应的 TC39 提案是“Well-Formed Unicode Strings”(正确格式的 Unicode 字符串)。

类似于几年前防止 JSON.stringify() 方法返回错误格式的 Unicode 字符串的提案,这个提案也涉及字符串是否为正确格式的 Unicode。

该提案在 String.prototype 上新增了两个原型方法:

  • String.prototype.isWellFormed()

  • String.prototype.toWellFormed()

02-1. String.prototype.isWellFormed()

String.prototype.isWellFormed() 用于判定字符串是否格式正确,具体而言,即字符串是否包含单独代理项(lone surrogates)。

举个栗子,该方法的基本操作如下所示:

const right = 'abc'
const wrong = 'ab\uD800c'

right.isWellFormed() // true,格式正确
wrong.isWellFormed() // false,格式错误

如你所见,上述代码中,字符串 wrong 包含了单独的后缀代理,所以判定结果为 false,即格式错误。

那这个冷门的原型方法关我屁事啊?我好像根本用不到啊......

是的没错,这个方法确实存在感较低,但当你实现某些 URL 相关的功能时,这个方法就有用武之地。比如你想封装一个涉及 URL 操作的 Vite 插件,或者一个 Axios 相关的后端服务,那么可能会使用 encodeURI() 等 API,在调用诸如此类的 API 之前,你就可以使用 String.prototype.isWellFormed() 来判定字符串的格式。

举个栗子,这是 Vite 游乐场源码的一段需要编码的 URL:

图片

2024 之前,遭遇这种需求,你可能需要自己手动封装同款功能,或者下载第三方库来实现。2024 之后,撸起袖子加油肝就完事了~

02-2. String.prototype.toWellFormed()

与上一个方法类似,String.prototype.toWellFormed() 用于将字符串所有错误的单独代理项替换为正确格式的 Unicode 字符。

假设我们有一个格式错误的 URL,就可以使用这个方法一键格式化。这是一个纯函数方法,即该方法会返回一个拷贝的副本,一个全新的字符串。

const url = 'https://bilibili.com/search?q=\uD800'

encodeURI(url.toWellFormed())
// "https://bilibili.com/search?q=%EF%BF%BD"
// 粉丝请注意,这可不是乱码!!!

如你所见,如果字符串判定为格式错误,下一步就可以直接使用这个方法正确格式化。

我在偷看 Axios 源码的时候就注意到了,Axios 需要针对 URL 和查询字符串等极端情况胆大心细地编码,那你说学不学嘛?

图片

03. 数组分组

数组分组对应的 TC39 提案是“Array Grouping”(数组分组)。

类似于前端工具人 lodash 中的 _.groupBy() 方法,数组分组提案在 Object 和 Map 上新增了两个静态方法:

  • Object.groupBy()

  • Map.groupBy()

历史总是惊人的相似!HTML5 卷走了 jQuery,ES6 也要卷走 lodash 了......如果前端生态也搞“开猿节流、降本增笑”,那么 lodash 指不定也要失业了!

03-1. Object.groupBy()

Object.groupBy() 静态方法可以基于传递的回调函数返回的字符串,对给定对象中的元素分组。

举个栗子,假设我有一个 fans 粉丝后援会数组,就可以使用这个方法对粉丝分门别类,基本操作如下所示:

const fans = [
  { name: '龙猫', type: '猫猫' },
  { name: '机器猫', type: '猫猫' },
  { name: '邓紫棋', type: '女粉' },
  { name: '冯提莫', type: '女粉' }
]

const result = Object.groupBy(fans, ({ type }) => type)

上述代码中,我们根据 type 对 fans 分组,结果如下图所示:

图片

可以看到,result 是一个已分组的对象,对象的键是 type 的值,对象的值是对应 type 的元素组成的数组。

fans 中有且仅有两种 type,所以我们的粉丝也被分为两组:

  • 一组是 '女粉'

  • 一组是 '猫猫'

03-2. Map.groupBy()

Map.groupBy() 静态方法和 Object.groupBy() 不能说是一模一样,只能说是大同小异。

粉丝请注意,两者的重要区别之一在于,Map.groupBy() 的返回值是一个 Map 对象,Object.groupBy() 的返回值则是一个无原型对象,即该对象的原型是 null

举个栗子,我们把 Object.groupBy() 替换为 Map.groupBy(),代码如下所示:

- const result = Object.groupBy(fans, ({ type }) => type)
+ const result = Map.groupBy(fans, ({ type }) => type)

结果如下图所示,如你所见,这次我们得到返回值是一个已分组 Map 对象,而不是一个无原型对象。

图片

04. 高潮总结

除了前文提及的若干新版功能之外,ES2024 还在正则表达式和 Buffer(二进制缓冲区)方面推陈出新。

完整版 ES2024 目前纳入新提案包括但不限于:

  • Promise.withResolvers() 提案

  • 正确格式的 Unicode 字符串提案

    • String.prototype.isWellFormed()

    • String.prototype.toWellFormed()

  • 数组分组提案

    • Map.groupBy()

    • Object.groupBy()

  • 正则表达式 v 标志提案

  • Atomics.waitAsync 提案

  • ArrayBuffer 转换提案

    • ArrayBuffer.prototype.detached

    • ArrayBuffer.prototype.transfer()

    • ArrayBuffer.prototype.transferToFixedLength()

  • 可调整大小的 ArrayBuffers 提案

    • ArrayBuffer.prototype.slice()

    • ArrayBuffer.prototype.resize()

    • ArrayBuffer.prototype.resizable

    • ArrayBuffer.prototype.byteLength

    • ArrayBuffer.prototype.maxByteLength

粉丝请注意,上述代码中,带 () 括号后缀的表示方法或函数,否则表示数据属性或访问器属性。

后面这几个提案相对小众,但尤其在 Node 等服务端开发或前端插件生态中,也有不可或缺的用武之地,相关技术细节请进阶阅读 MDN 电子书或 ES 语言说明书。哥哥带进门,修行看个人,大家可以当做课后作业去深度学习。

参考文献

  1. ECMA262:https://tc39.es/ecma262

  2. MDN:https://developer.mozilla.org

  3. TC39:https://github.com/tc39

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值