ECMAScript 2024 (ES15) 来啦!看看都有什么新功能吧!

Hello,大家好,我是 Sunday。

ECMAScript语言规范每年更新一次,备受期待的ECMAScript 2024计划于2024年6月正式亮相。目前,ECMAScript 2024的候选版本已经发布,带来了一系列实用的新功能。让我们深入研究它们,看看它们能提供什么!

01:Promise.with Resolver()

使用Promise.with Resolers()函数可以创建新的Promise,同时获得ResolveReject函数。这在某些情况下特别有用,特别是当您需要同时访问 resolvereject 功能时。

javascript 复制代码
const { promise, resolve, reject } = Promise.withResolvers();

setTimeout(() => resolve('Success!'), 1000);

promise.then(value => {
  console.log(value); // Outputs: Success!
});

在这个例子中,我们首先使用 Promise.withResolvers()创建一个新的Promise,获得resolvereject函数。然后,我们使用resolve函数在setTimeout回调中解析这个Promise。最后,添加一个.then处理程序来处理Promise的解析值。

使用Promise.withResolvers()的关键区别在于,resolvereject函数现在与Promise本身处于同一作用域中,而不是在执行器中创建并使用一次。这可以实现一些更高级的用例,例如:在重复事件中重用它们,特别是在处理流和队列时。这通常也意味着与在执行器内包装大量逻辑相比,嵌套更少。

这个特性对于需要对 Promise 的状态进行更精细控制或者在 Promise 创建后仍需要访问 resolvereject 函数的场景非常有用。

02:Object.groupBy / Map.groupBy

Object.groupByMap.groupBy 方法用于对数组进行分组。

假设你有一个由表示个人的对象组成的数组,并且需要按年龄对其进行分组。你可以使用 forEach 循环实现这一点,如下所示:

ini 复制代码
const people = [
  { name: "Alice", age: 28 },
  { name: "Bob", age: 30 },
  { name: "Eve", age: 28 },
];

const peopleByAge = {};

people.forEach((person) => {
  const age = person.age;
  if (!peopleByAge[age]) {
    peopleByAge[age] = [];
  }
  peopleByAge[age].push(person);
});

console.log(peopleByAge);

输出为:

json 复制代码
{
  "28": [{"name":"Alice","age":28}, {"name":"Eve","age":28}],
    "30": [{"name":"Bob","age":30}]
}

你还可以使用reduce方法:

ini 复制代码
const peopleByAge = people.reduce((acc, person) => {
  const age = person.age;
  if (!acc[age]) {
    acc[age] = [];
  }
  acc[age].push(person);
  return acc;
}, {});

无论使用哪种方法,这段代码都有些繁琐。每次都需要检查对象,看看分组键是否存在,如果不存在,则创建一个空数组并向其中添加项目。

使用 Object.groupBy 简化处理

但是如果使用 Object.groupBy 就会方便很多

javascript 复制代码
const peopleByAge = Object.groupBy(people, (person) => person.age);

然而,重要的是要注意,使用 Object.groupBy 返回一个没有原型的对象。这意味着该对象不会继承任何属性或方法来自 Object.prototype,比如 hasOwnPropertytoString。虽然这可以避免意外覆盖 Object.prototype 上的属性,但也意味着一些与对象相关的方法无法使用。

javascript 复制代码
const peopleByAge = Object.groupBy(people, (person) => person.age);
console.log(peopleByAge.hasOwnProperty("28")); // TypeError:PeopleByAge.hasOwnProperty不是函数

在调用 Object.groupBy 时,传递给它的回调函数应该返回一个字符串或 Symbol 类型的值。如果回调函数返回另一种类型的值,它将被强制转换为字符串。

在这个例子中,回调函数返回一个数值类型的年龄属性值,但由于 Object.groupBy 方法要求键必须是字符串或 Symbol 类型,这个数字将被强制转换为字符串类型。

使用Map.groupBy进行排序

Map.groupByObject.groupBy 基本上做的是同样的事情,只是 Map.groupBy 返回一个 Map 对象,而不是普通对象。

ini 复制代码
const ceo = { name: "Jamie", age: 40, reportsTo: null };
const manager = { name: "Alice", age: 28, reportsTo: ceo };

const people = [
  ceo
  manager,
  { name: "Bob", age: 30, reportsTo: manager },
  { name: "Eve", age: 28, reportsTo: ceo },
  ];

const peopleByManager = Map.groupBy(people, (person) => person.reportsTo);

这里,people 是按 manage 进行分组的。如果你想使用对象从此 Map 中检索数据,那么这些对象必须具有相同的标识或引用。这是因为 Map 在比较键(key)时使用严格相等(===),这意味着只有具有相同引用的两个对象才能被视为相同的键。

php 复制代码
peopleByManager.get(ceo); // => [{ name: "Alice", age: 28, reportsTo: ceo }, { name: "Eve", age: 28, reportsTo: ceo }]
peopleByManager.get({ name: "Jamie", age: 40, reportsTo: null }); // => undefined

在上面的例子中,如果你尝试使用类似 ceo 对象作为键来访问 Map 中的数据,你将无法检索到相应的值,因为这个对象与之前存储在 Map 中的 ceo 对象不同。

03:ArrayBuffer.prototype.resize

ArrayBuffer 实例的 resize() 方法会将 ArrayBuffer 调整到指定的大小(以字节为单位),前提是该 ArrayBuffer 是可调整大小的,并且新的大小小于或等于该 ArrayBuffermaxByteLength

arduino 复制代码
const buffer = new ArrayBuffer(8, { maxByteLength: 16 });

console.log(buffer.byteLength); // 8

if (buffer.resizable) {
  console.log("Buffer size is resizable!");
  buffer.resize(12);
}

04:ArrayBuffer.prototype.transfer

transfer() 方法执行的操作与结构化克隆算法相同。它将当前 ArrayBuffer 的字节复制到一个新的 ArrayBuffer 对象中,然后分离当前的 ArrayBuffer 对象,保留其大小可调整性。

ini 复制代码
// 创建一个ArrayBuffer并向其中写入一些字节
const buffer = new ArrayBuffer(8);
const view = new Uint8Array(buffer);
view[1] = 2;
view[7] = 4;

// 将缓冲区复制到另一个相同大小的缓冲区
const buffer2 = buffer.transfer();
console.log(buffer.detached); // true
console.log(buffer2.byteLength); // 8
const view2 = new Uint8Array(buffer2);
console.log(view2[1]); // 2
console.log(view2[7]); // 4

// 将缓冲区复制到较小的缓冲区
const buffer3 = buffer2.transfer(4);
console.log(buffer3.byteLength); // 4
const view3 = new Uint8Array(buffer3);
console.log(view3[1]); // 2
console.log(view3[7]); // undefined

// 将缓冲区复制到更大的缓冲区
const buffer4 = buffer3.transfer(8);
console.log(buffer4.byteLength); // 8
const view4 = new Uint8Array(buffer4);
console.log(view4[1]); // 2
console.log(view4[7]); // 0

// 已分离,引发 TypeError
buffer.transfer(); // TypeError: Cannot perform ArrayBuffer.prototype.transfer on a detached ArrayBuffer

05:Atomics.waitAsync()

Atomics.waitAsync() 静态方法异步等待共享内存中的特定位置,并返回一个 Promise。与 Atomics.wait() 不同,waitAsync非阻塞的,可以在主线程中使用。

ini 复制代码
const sab = new SharedArrayBuffer(1024);
const int32 = new Int32Array(sab);

让一个读线程在位置0休眠并等待,期望该位置的值为0。结果.值将是一个 promise 。

go 复制代码
const result = Atomics.waitAsync(int32, 0, 0, 1000);
// { async: true, value: Promise {<pending>} }

06:正则 "v" 标记

正则表达式中的 v 标志,也称为 RegExp v 标志,是 u 标志的超集,并提供了两个额外的功能:

Unicode 属性转义

使用 Unicode 属性转义,您可以利用字符串的属性。

javascript 复制代码
const re = /^\p{RGI_Emoji}$/v;

// 匹配仅包含1个代码点的表情符号:
re.test('⚽'); // '\u26BD'
// → true ✅

// 匹配由多个代码点组成的表情符号:
re.test('👨🏾⚕️'); // '\u{1F468}\u{1F3FE}\u200D\u2695\uFE0F'
// → true ✅

集合操作

它允许在字符类之间进行集合操作。

javascript 复制代码
const re = /[\p{White_Space}&&\p{ASCII}]/v;
re.test('\n'); // → true
re.test('\u2028'); // → false

前端训练营:1v1私教,终身辅导计划,帮你拿到满意的 offer 已帮助数百位同学拿到了中大厂 offer。欢迎来撩~~~~~~~~

相关推荐
前端之虎陈随易4 小时前
编程语言级别的Skill市场,AI Agent 的未来形态
前端·vue.js·人工智能·typescript·node.js
一路向北he4 小时前
字节钢铁军团--“提供情境,而非控制”
java·开发语言·前端
kyriewen4 小时前
豆包和千问同时关了智能体,我用它们搭的 3 个自动化全废了——迁移方案整理
前端·javascript·ai编程
前端一小卒4 小时前
我用 TypeScript 从零手写了一个 Claude Code,然后发现它的核心只有 30 行
前端·agent
大圣编程6 小时前
Python中continue语句的用法是什么?
开发语言·前端·python
yuhaiqiang6 小时前
随手 vibecoding 的浏览器插件已经 6000 多次下载,聊聊他的产品设计
前端·后端·面试
之歆6 小时前
Vue商品详情与放大镜组件
前端·javascript·vue.js
再吃一根胡萝卜7 小时前
如何把小米 MiMo 接入 CodeBuddy,打造私有 Agent
前端
负责的蛋挞8 小时前
异步HttpModule的实现方式
java·服务器·前端
用户852495071849 小时前
从零构建 MCP 文件服务:50 行代码让 AI 读懂你的文件
程序员