文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

ECMAScript 2024 正式发布,新特性一览!

2024-11-29 21:13

关注

图片

下面就来看看 ECMAScript 2024 都有哪些新特性吧!

Promise.withResolvers()

Promise.withResolvers() 允许创建一个新的 Promise,并同时获得 resolve 和 reject 函数。

Promise.withResolvers() 等同于以下代码,不过代码会更简洁:

let resolve, reject;
const promise = new Promise((res, rej) => {
  resolve = res;
  reject = rej;
});

通常,当创建一个新的 Promise 时,会传递一个执行器函数给 Promise 构造函数,这个执行器函数接收两个参数:resolve 和 reject 。但在某些情况下,可能想要在 Promise 创建之后仍然能够访问到这两个函数。这就是 Promise.withResolvers() 的用武之地。

使用 Promise.withResolvers() 的例子:

const { promise, resolve, reject } = Promise.withResolvers();  
  
// 在这里可以使用 resolve 和 reject 函数  
setTimeout(() => resolve('成功!'), 8000);  
  
promise.then(value => {  
  console.log(value); // 输出: 成功!  
});

使用 Promise.withResolvers() 关键的区别在于resolve 和 reject函数现在与 Promise 本身处于同一作用域,而不是在执行器中被创建和一次性使用。这可能使得一些更高级的用例成为可能,例如在重复事件中重用它们,特别是在处理流和队列时。这通常也意味着相比在执行器内包装大量逻辑,嵌套会更少。这个方法对于那些需要更细粒度控制 Promise 的状态,或者在 Promise 创建后仍然需要访问 resolve 和 reject 函数的场景来说非常有用。

浏览器支持:

图片

Object.groupBy() / Map.groupBy()

Object.groupBy() 和 Map.groupBy() 方法用于数组分组。

假设有一个由表示水果的对象组成的数组,需要按照颜色进行分组。以前可以使用forEach循环来实现,代码如下:

const fruits = [  
  { name: "Apple", color: "red" },  
  { name: "Banana", color: "yellow" },  
  { name: "Cherry", color: "red" },  
  { name: "Lemon", color: "yellow" },  
  { name: "Grape", color: "purple" },  
];

const fruitsByColor = {};  

fruits.forEach(fruit => {  
  const color = fruit.color;  
  if (!fruitsByColor[color]) {  
    fruitsByColor[color] = [];  
  }  
  fruitsByColor[color].push(fruit);  
}); 

console.log(fruitsByColor);

输出结果如下:

图片

也可以使用reduce方法:

const fruitsByColor = fruits.reduce((acc, fruit) => {  
  const color = fruit.color;  
  if (!acc[color]) {  
    acc[color] = [];  
  }  
  acc[color].push(fruit);  
  return acc;  
}, {});

无论哪种方式,代码都略显繁琐。每次都要检查对象,看分组的 key 是否存在,如果不存在,则创建一个空数组,并将项目添加到该数组中。

Object.groupBy()

可以通过以下方式来使用新的Object.groupBy方法,代码更简洁:

const fruitsByColor = Object.groupBy(fruits, (fruit) => fruit.color);

需要注意,使用Object.groupBy方法返回一个没有原型(即没有继承任何属性和方法)的对象。这意味着该对象不会继承Object.prototype上的任何属性或方法,例如hasOwnProperty或toString等。虽然这样做可以避免意外覆盖Object.prototype上的属性,但也意味着不能使用一些与对象相关的方法。

const fruitsByColor = Object.groupBy(fruits, (fruit) => fruit.color);
console.log(fruitsByColor.hasOwnProperty("red"));
// TypeError: fruitsByColor.hasOwnProperty is not a function

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

浏览器支持:

图片

Map.groupBy()

Map.groupBy和Object.groupBy的功能一样,只是返回的结果类型不同。Map.groupBy返回一个 Map 对象,而Object.groupBy返回一个普通对象。

const fruits = [  
  { name: "Apple", color: "red" },  
  { name: "Banana", color: "yellow" },  
  { name: "Cherry", color: "red" },  
  { name: "Lemon", color: "yellow" },  
  { name: "Grape", color: "purple" },  
];

const fruitsByColor = Map.groupBy(fruits, (fruit) => fruits.color);

这里根据水果颜色进行了分组,输出结果如下:

图片

可以通过 Map 的 get 方法来来获取分组分组结果:

fruitsByColor.get("red");
// [{"name": "Apple", "color": "red"}, {"name": "Cherry", "color": "red"}]

浏览器支持:

String:isWellFormed() / toWellFormed()

String.prototype.isWellFormed()

isWellFormed() 用于检查一个 UTF-16 编码的字符串是否包含孤立的代理项(即未与另一个代理项配对的高代理或低代理)。UTF-16使用代理对来表示Unicode中超过基本多文种平面的字符。一个有效的UTF-16字符串应该只包含正确配对的代理对或单独的BMP字符。

下面来看一个例子

const strings = [
  // 单独的前导代理
  "ab\uD800",
  "ab\uD800c",
  // 单独的后尾代理
  "\uDFFFab",
  "c\uDFFFab",
  // 格式正确
  "abc",
  "ab\uD83D\uDE04c",
];

for (const str of strings) {
  console.log(str.isWellFormed());
}
// 输出:
// false
// false
// false
// false
// true
// true

如果传递的字符串格式不正确, encodeURI 会抛出错误。可以通过使用 isWellFormed() 在将字符串传递给 encodeURI() 之前测试字符串来避免这种情况。

const illFormed = "https://example.com/search?q=\uD800";

try {
  encodeURI(illFormed);
} catch (e) {
  console.log(e); // URIError: URI malformed
}

if (illFormed.isWellFormed()) {
  console.log(encodeURI(illFormed));
} else {
  console.warn("Ill-formed strings encountered."); // Ill-formed strings encountered.
}

isWellFormed() 函数的使用场景主要包括以下几种情况:

浏览器支持:

图片

String.prototype.toWellFormed()

toWellFormed() 方法返回一个字符串,其中该字符串的所有单独代理项都被替换为 Unicode 替换字符 U+FFFD。

toWellFormed() 迭代字符串的码元,并将任何单独代理项替换为 Unicode 替换字符 U+FFFD。这确保了返回的字符串格式正确并可用于期望正确格式字符串的函数,比如 encodeURI。由于引擎能够直接访问字符串的内部表示,与自定义实现相比 toWellFormed() 更高效。

const strings = [
  // 单独的前导代理
  "ab\uD800",
  "ab\uD800c",
  // 单独的后尾代理
  "\uDFFFab",
  "c\uDFFFab",
  // 格式正确
  "abc",
  "ab\uD83D\uDE04c",
];

for (const str of strings) {
  console.log(str.toWellFormed());
}
// 输出:
// "ab�"
// "ab�c"
// "�ab"
// "c�ab"
// "abc"
// "ab😄c"

如果传递的字符串格式不正确, encodeURI 会抛出错误。可以先通过使用 toWellFormed() 将字符串转换为格式正确的字符串来避免这种情况。

const illFormed = "https://example.com/search?q=\uD800";

try {
  encodeURI(illFormed);
} catch (e) {
  console.log(e); // URIError: URI malformed
}

console.log(encodeURI(illFormed.toWellFormed())); // "https://example.com/search?q=%EF%BF%BD"

浏览器支持:

图片

ArrayBuffer:resize / transfer

ArrayBuffer.prototype.resize

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

const buffer = new ArrayBuffer(8, { maxByteLength: 16 });

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

if (buffer.resizable) {
  console.log("缓冲区大小是可调整的!");
  buffer.resize(12);
}

注意:

浏览器支持:

ArrayBuffer.prototype.transfer

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

// 创建一个 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

浏览器支持:

图片

Atomics.waitAsync()

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

下面来看一个简单的例子,给定一个共享的 Int32Array。

const sab = new SharedArrayBuffer(1024);
const int32 = new Int32Array(sab);

令一个读取线程休眠并在位置 0 处等待,预期该位置的值为 0。result.value 将是一个 promise。

const result = Atomics.waitAsync(int32, 0, 0, 1000);
// { async: true, value: Promise {} }

在该读取线程或另一个线程中,对内存位置 0 调用以令该 promise 解决为 "ok"。

Atomics.notify(int32, 0);
// { async: true, value: Promise {: 'ok'} }

如果它没有解决为 "ok",则共享内存该位置的值不符合预期(value 将是 "not-equal" 而不是一个 promise)或已经超时(该 promise 将解决为 "time-out")。

浏览器支持:

图片

正则表达式 v 标志

RegExp 的 v 标志是 u 标志的超集,并提供了另外两个功能:

const re = /^\p{RGI_Emoji}$/v;

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

// 匹配由多个代码点组成的表情符号:
re.test('👨🏾⚕️'); // '\u{1F468}\u{1F3FE}\u200D\u2695\uFE0F' // true
const re = /[\p{White_Space}&&\p{ASCII}]/v;
re.test('\n'); // true
re.test('\u2028'); // false

那 u 标志是干什么的呢?

在 JavaScript 中,RegExp 对象的 u 标志(也称为 Unicode 标志)是用于处理 Unicode 字符的。当在正则表达式字面量或构造函数中使用 u 标志时,它将改变正则表达式的行为,以便更准确地处理 Unicode 字符。以下是 u 标志的主要作用:

  1. 完整 Unicode 字符匹配: 在 Unicode 中,有些字符是由多个“代码单元”(在 UTF-16 编码中)组成的,如表情符号或某些特殊字符。不使用 u 标志时,正则表达式可能会将这些字符拆分成多个代码单元,导致不正确的匹配。使用 u 标志后,正则表达式会将整个字符视为一个单位,从而进行更准确的匹配。
  2. Unicode 属性的支持: 使用 u 标志的正则表达式可以访问 Unicode 字符的属性,如是否为大写字母、是否为标点符号等。这可以通过在正则表达式中使用 \p{...} 和 \P{...} 序列来实现,其中 {...} 中是 Unicode 属性的名称。
  3. Unicode 字符类别的支持: 与 Unicode 属性类似,使用 u 标志的正则表达式还可以支持 Unicode 字符类别,如 \p{Letter} 匹配任何字母字符,\p{Number} 匹配任何数字字符等。
  4. 点号(.)的新行为: 在默认情况下,正则表达式中的点号(.)不匹配换行符,但会匹配任何单个字符(在 UTF-16 编码中是一个代码单元)。但是,当使用 u 标志时,点号将匹配任何单个 Unicode 字符,包括那些由多个 UTF-16 代码单元组成的字符。
  5. 对量词和边界断言的改进: 使用 u 标志的正则表达式将改进对 Unicode 字符的量词(如 *, +, ?, {n}, {n,}, {n,m})和边界断言(如 ^ 和 $)的处理。这确保了它们在整个 Unicode 字符上正确工作,而不是仅仅在 UTF-16 代码单元上。
  6. 更准确的字符类: 使用 u 标志的正则表达式将更准确地解释字符类,如 [a-z]。在不使用 u 标志时,这个字符类可能只匹配基本的拉丁字母。但是,使用 u 标志后,它将根据 Unicode 标准来匹配任何被视为“小写字母”的字符,包括来自其他语言的小写字母。

下面是一个使用 u 标志的例子:

const regex = /^\p{Letter}+$/u;  
console.log(regex.test('你好')); // 输出:true  
console.log(regex.test('123')); // 输出:false

在这个例子中,正则表达式 \p{Letter}+ 匹配一个或多个 Unicode 字母字符。由于 '你好' 包含两个 Unicode 字母字符(即使它们在 UTF-16 编码中由多个代码单元组成),所以 regex.test('你好') 返回 true。而 '123' 不包含任何 Unicode 字母字符,所以 regex.test('123') 返回 false。

来源:前端充电宝内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯