一年一次,ES2024 新鲜出炉的 JS 特性先睹为快!

发布于:2024-05-10 ⋅ 阅读:(41) ⋅ 点赞:(0)

给前端以福利,给编程以复利。大家好,我是大家的林语冰。

00. 论文背景

2024.png

今年我们翘首以盼的 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 传递的回调函数内部,至少调用一个 resolvereject冻态函数”,用来冻结 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 变量来延迟赋值,同时在回调函数外部自由调用 resolvereject

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

更妙的是,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:

vite.png

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 和查询字符串等极端情况胆大心细地编码,那你说学不学嘛?

axios.png

03. 数组分组

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

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

  • 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)

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

log.png

可以看到,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 对象,而不是一个无原型对象。

map.png

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
  2. MDN
  3. TC39

粉丝互动

本期话题是:如何评价最新的 ES2024,你觉得哪个新功能最棒,或者最期待其他哪些功能?你可以在本文下方自由言论,文明科普。

欢迎持续关注“前端俱乐部”,给前端以福利,给编程以复利。

坚持阅读的小伙伴可以给自己点赞!谢谢大家的点赞,掰掰~


网站公告

今日签到

点亮在社区的每一天
去签到