Hello,大家好,我是 Sunday。
ECMAScript语言规范每年更新一次,备受期待的ECMAScript 2024计划于2024年6月正式亮相。目前,ECMAScript 2024的候选版本已经发布,带来了一系列实用的新功能。让我们深入研究它们,看看它们能提供什么!
01:Promise.with Resolver()
使用Promise.with Resolers()
函数可以创建新的Promise
,同时获得Resolve
和Reject
函数。这在某些情况下特别有用,特别是当您需要同时访问 resolve
和 reject
功能时。
javascript
const { promise, resolve, reject } = Promise.withResolvers();
setTimeout(() => resolve('Success!'), 1000);
promise.then(value => {
console.log(value); // Outputs: Success!
});
在这个例子中,我们首先使用 Promise.withResolvers()
创建一个新的Promise
,获得resolve
和reject
函数。然后,我们使用resolve
函数在setTimeout
回调中解析这个Promise
。最后,添加一个.then
处理程序来处理Promise
的解析值。
使用Promise.withResolvers()
的关键区别在于,resolve
和reject
函数现在与Promise
本身处于同一作用域中,而不是在执行器中创建并使用一次。这可以实现一些更高级的用例,例如:在重复事件中重用它们,特别是在处理流和队列时。这通常也意味着与在执行器内包装大量逻辑相比,嵌套更少。
这个特性对于需要对 Promise
的状态进行更精细控制或者在 Promise
创建后仍需要访问 resolve
和 reject
函数的场景非常有用。
02:Object.groupBy / Map.groupBy
Object.groupBy
和 Map.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
,比如 hasOwnProperty
或 toString
。虽然这可以避免意外覆盖 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.groupBy
和 Object.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
是可调整大小的,并且新的大小小于或等于该 ArrayBuffer
的 maxByteLength
。
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
。欢迎来撩~~~~~~~~