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。欢迎来撩~~~~~~~~

相关推荐
小白学习日记41 分钟前
【复习】HTML常用标签<table>
前端·html
丁总学Java1 小时前
微信小程序-npm支持-如何使用npm包
前端·微信小程序·npm·node.js
yanlele1 小时前
前瞻 - 盘点 ES2025 已经定稿的语法规范
前端·javascript·代码规范
懒羊羊大王呀2 小时前
CSS——属性值计算
前端·css
DOKE2 小时前
VSCode终端:提升命令行使用体验
前端
xgq2 小时前
使用File System Access API 直接读写本地文件
前端·javascript·面试
用户3157476081352 小时前
前端之路-了解原型和原型链
前端
永远不打烊2 小时前
librtmp 原生API做直播推流
前端
北极小狐2 小时前
浏览器事件处理机制:从硬件中断到事件驱动
前端
无咎.lsy2 小时前
vue之vuex的使用及举例
前端·javascript·vue.js