一年一次,ES2024 新鲜出炉的 JS 特性先睹为快!今年我们翘首以盼的 ES2024(正式版)即将在下个月正式上线啦
给前端以福利,给编程以复利。大家好,我是大家的林语冰。
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 语言说明书。哥哥带进门,修行看个人,大家可以当做课后作业去深度学习。
参考文献
- ECMA262:tc39.es/ecma262
- MDN:developer.mozilla.org
- TC39:github.com/tc39
粉丝互动
本期话题是:如何评价最新的 ES2024,你觉得哪个新功能最棒,或者最期待其他哪些功能?你可以在本文下方自由言论,文明科普。
欢迎持续关注“前端俱乐部”,给前端以福利,给编程以复利。
坚持阅读的小伙伴可以给自己点赞!谢谢大家的点赞,掰掰~
转载自:https://juejin.cn/post/7366966322474188841