ES14 (ES2023)
ES2023(ES14)引入了一系列实用的新特性,包括从右向左查找数组元素的方法、Hashbang语法支持、不修改原数组的数组操作方法、Set集合的增强功能以及允许Symbol作为WeakMap键。这些更新使JavaScript代码在处理数组和集合时更加灵活,同时提供了更好的脚本执行和内存管理能力。
ES2023(ES14)带来的新特性有:
- findLast( ) 和 findLastIndex( )
- Hashbang 语法
- Change Array by Copy Methods
- Set 方法的增强
- Symbols as WeakMap keys
1. findLast( ) 和 findLastIndex( )
findLast( ) 和 findLastIndex( ) 为数组提供了一种从右到左查找元素的方法,类似于 find( ) 和 findIndex( ),但从数组的末尾开始查找。
const arr = [11, 24, 13, 74, 55];
console.log(arr.find((x) => x % 2 === 0));
console.log(arr.findIndex((x) => x % 2 === 0));
console.log(arr.findLast((x) => x % 2 === 0));
console.log(arr.findLastIndex((x) => x % 2 === 0));
2. Hashbang 语法
Hashbang Grammar 是一个常见的 Unix 特性,用于告诉系统应该使用哪个解释器来运行脚本文件。
在 Unix 和 Linux 环境中,hashbang (#!) 是脚本文件的第一行,通常用于指定该脚本应由哪个解释器运行。这样,脚本文件可以直接作为可执行文件运行,而不必手动调用解释器。
例如,传统的 Unix 脚本文件的开头可能是:
#!/usr/bin/env bash
这表示使用 /usr/bin/env 运行 bash 解释器来执行该脚本。
ES2023 引入了 Hashbang Grammar 特性,允许 JS 文件在文件的第一行包含 hashbang(#!),从而使 JS 文件可以在类似 Unix 的环境中直接执行,而不需要明确地调用解释器(如 node)
#!/usr/bin/env node
console.log('Hello, World!');
在这个例子中,#!/usr/bin/env node 指定了使用 node 作为解释器。当你在 Unix/Linux 系统中执行这个文件时,系统会自动使用 node 来运行它,而不需要手动输入 node filename.js
注意点1:如果直接执行,可能会报错:zsh: permission denied: ./index.js
这表示文件没有执行权限。解决方案也很简单,在终端中使用 chmod 命令为文件添加执行权限。运行以下命令:
chmod +x ./index.js在确保文件有可执行权限后,运行以下命令来执行 index.js:
./index.js
注意点2:在 Windows 中的限制
hashbang 语法通常在 Unix 和 Linux 环境下工作,而不是直接在 Windows 环境下。
对于 Windows,通常需要手动调用解释器(例如,使用 node index.js)
实战应用案例
开发一个简单的命令行工具,具有以下功能:
-
添加任务:将新的任务添加到任务列表中
./todo.js add "完成项目文档"
./todo.js add "部署应用到生产环境" -
查看任务:列出所有待办任务
./todo.js list -
标记任务为已完成:将某个任务标记为已完成
./todo.js complete 1 -
删除任务:从任务列表中删除已完成的任务
./todo.js clear
3. Change Array by Copy Methods
新增了一些数组方法,这些方法在不修改原数组的情况下返回操作后的新数组。这些方法包括:
- toReversed( ):返回一个反转后的新数组
- toSorted( ):返回排序后的新数组(基于可选的比较函数)
- toSpliced( ):返回移除或替换部分元素的新数组(基于 splice 操作)
- with( ):返回一个替换指定索引的新数组
const arr = [1, 2, 3, 4, 5];
console.log(arr.toReversed());
console.log(arr);
console.log(arr.toSorted((a, b) => b - a));
console.log(arr);
console.log(arr.toSpliced(1, 3)); // 包含了结束下标
console.log(arr);
console.log(arr.with(0, 100));
console.log(arr);
4. Set 方法的增强
ES2023 新增了一些适用于 Set 数据结构的方法,这些方法主要是和集合操作相关的。包括:
- Set.prototype.intersection( ):返回两个集合的交集
- Set.prototype.union( ):返回两个集合的并集
- Set.prototype.difference():返回两个集合的差集
- Set.prototype.symmetricDifference():返回两个集合的对称差集
- Set.prototype.isDisjointFrom():判断两个集合是否不相交
const setA = new Set([1, 2, 3]);
const setB = new Set([3, 4, 5]);
console.log(setA.intersection(setB));
console.log(setA.union(setB));
console.log(setA.difference(setB)); // 差集,返回在 A 中但不在 B 中的元素
console.log(setA.symmetricDifference(setB)); // 对称差集,返回在 A 或 B 中,但不会同时出现在 A 和 B 中的元素
console.log(setA.isDisjointFrom(setB)); // 是否互斥,返回 A 和 B 是否没有交集
5. Symbols as WeakMap keys
在 ES2023 之前,WeakMap 和 WeakSet 的键只能是对象,而不能是 Symbol。这种限制的原因是 Symbol 不像对象那样容易被垃圾回收,因此无法作为弱引用的键。为了扩展 JS 的弱引用集合的功能,ES2023 引入了这一特性,未注册的 Symbol 可以作为 WeakMap 和 WeakSet 的键。
所谓未注册Symbol指的就是不是使用 Symbol.for 生成Symbol
示例 1:在 WeakMap 中使用 Symbol 作为键
let s = Symbol("foo"); // 未注册的 Symbol
let obj = {
name: "bar",
};
let wm = new WeakMap();
// 在ES2023之前,weakmap的键只能是对象,不能是Symbol
// 但是在ES2023中,WeakMap的键可以是Symbol
wm.set(s, obj);
console.log(wm.get(s)); // { name: 'bar' }
示例 2:在 WeakSet 中使用 Symbol
let s = Symbol("foo"); // 未注册的 Symbol
let ws = new WeakSet();
ws.add(s);
console.log(ws.has(s)); // true
示例 3:WeakRef 和 FinalizationRegistry 支持 Symbol
let sym = Symbol("foo");
let wr = new WeakRef(sym);
console.log(wr.deref()); // 输出: Symbol(foo)
let fr = new FinalizationRegistry((value) => {
console.log("Finalized:", value);
});
let obj = { name: "bar" };
fr.register(obj, "bar", sym);
fr.unregister(sym);
在这个例子中,WeakRef 也支持 Symbol。此外,FinalizationRegistry 也可以使用 Symbol 进行注册和取消注册。
尽管 Symbol 现在可以作为 WeakMap 和 WeakSet 的键,但注册的 Symbol(通过 Symbol.for() 注册的符号)仍然不能作为键。这是因为注册的符号全局共享,并且不会被垃圾回收,因此不适合作为弱引用的键。
let s = Symbol.for("foo"); // 注册的 Symbol
let obj = {
name: "bar",
};
let wm = new WeakMap();
// 注册的Symbol不能作为WeakMap的键
wm.set(s, obj);
// TypeError: Invalid value used as weak map key
-EOF-