编程进阶网 编程进阶网
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • C语言入门精通

  • Cpp入门到精通

  • Java入门精通

  • Go入门到精通

  • JavaScript入门

    • 基础入门

      • README
      • 入门介绍
      • 数据类型
      • 运算符
      • 函数
      • 面向对象
      • 标准库
      • 异步操作
      • 事件设计
      • 错误机制
      • 模块开发
      • 字符串处理
      • 迭代器与生成器
      • Symbol
        • 13.1 Symbol 基础
          • 13.1.1 创建 Symbol
          • 13.1.2 Symbol 作为属性键
          • 13.1.3 Symbol.for() 全局注册表
        • 13.2 内置 Symbol
          • 13.2.1 Symbol.iterator
          • 13.2.2 Symbol.asyncIterator
          • 13.2.3 Symbol.toPrimitive
          • 13.2.4 Symbol.hasInstance
          • 13.2.5 Symbol.species
          • 13.2.6 Symbol.toStringTag
          • 13.2.7 Symbol.isConcatSpreadable
          • 13.2.8 其他内置 Symbol
          • 13.2.9 内置 Symbol 总览
        • 13.3 WeakRef 与 FinalizationRegistry
          • 13.3.1 WeakRef(弱引用)
          • 13.3.2 FinalizationRegistry(回调清理)
        • 13.4 装饰器(Decorators)
          • 13.4.1 类装饰器
          • 13.4.2 方法装饰器
          • 13.4.3 属性装饰器
          • 13.4.4 auto-accessor 装饰器
        • 13.5 using 声明与显式资源管理
          • 13.5.1 同步资源管理
          • 13.5.2 异步资源管理
          • 13.5.3 DisposableStack
        • 13.6 其他 ES2020-2024 重要特性
          • 13.6.1 structuredClone(ES2022)
          • 13.6.2 Error cause(ES2022)
          • 13.6.3 Array 新方法(ES2023)
          • 13.6.4 Hashbang 语法(ES2023)
          • 13.6.5 Promise.withResolvers(ES2024)
          • 13.6.6 Object.groupBy / Map.groupBy(ES2024)
          • 13.6.7 Top-level await(ES2022)
          • 13.6.8 正则表达式 v 标志(ES2024)
      • DOM操作
      • 网络请求
    • 综合案例

    • 专栏博客

  • CodeX
  • JavaScript入门
  • 基础入门
杨充
2026-04-13
目录

Symbol

# 13.Symbol与新特性

Symbol 是 ES6 引入的第七种原始数据类型,主要用于创建对象的唯一属性键,避免命名冲突。除了自定义 Symbol,JavaScript 还定义了一系列内置 Symbol 来控制对象的底层行为。本章同时涵盖 ES2020-ES2024 的重要新特性。

# 13.1 Symbol 基础

# 13.1.1 创建 Symbol

// 基本创建
const s1 = Symbol();
const s2 = Symbol();
console.log(s1 === s2); // false(每个 Symbol 都是唯一的)

// 带描述(仅用于调试,不影响唯一性)
const s3 = Symbol('description');
const s4 = Symbol('description');
console.log(s3 === s4);        // false
console.log(s3.toString());    // 'Symbol(description)'
console.log(s3.description);   // 'description'(ES2019)

// Symbol 不能用 new 调用
// new Symbol(); // TypeError
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 13.1.2 Symbol 作为属性键

const id = Symbol('id');
const name = Symbol('name');

const user = {
    [id]: 12345,
    [name]: 'Alice',
    age: 25
};

// 访问
console.log(user[id]);    // 12345
console.log(user[name]);  // 'Alice'

// Symbol 属性不出现在常规遍历中
console.log(Object.keys(user));                  // ['age']
console.log(JSON.stringify(user));               // '{"age":25}'
console.log(Object.getOwnPropertyNames(user));   // ['age']

// 专门获取 Symbol 属性
console.log(Object.getOwnPropertySymbols(user)); // [Symbol(id), Symbol(name)]
console.log(Reflect.ownKeys(user));              // ['age', Symbol(id), Symbol(name)]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

这使得 Symbol 适合定义库内部使用的属性,不会与用户定义的属性冲突。

# 13.1.3 Symbol.for() 全局注册表

// Symbol.for() 在全局注册表中查找或创建 Symbol
const s1 = Symbol.for('shared');
const s2 = Symbol.for('shared');
console.log(s1 === s2); // true(同一个 Symbol)

// Symbol.keyFor() 查找全局 Symbol 的键
console.log(Symbol.keyFor(s1)); // 'shared'

// 普通 Symbol 不在注册表中
const local = Symbol('local');
console.log(Symbol.keyFor(local)); // undefined

// 全局注册表跨 iframe 和 Service Worker 共享
1
2
3
4
5
6
7
8
9
10
11
12
13

使用场景对比:

方式 唯一性 跨作用域共享 适用场景
Symbol() 总是唯一 不可共享 私有属性、防冲突
Symbol.for() 按键名共享 全局共享 跨模块通信、插件系统

# 13.2 内置 Symbol

JavaScript 定义了 13 个内置 Symbol,用于自定义对象的底层行为。

# 13.2.1 Symbol.iterator

定义对象的默认迭代器,使其可以被 for...of 遍历:

class Pagination {
    constructor(items, pageSize) {
        this.items = items;
        this.pageSize = pageSize;
    }
    
    *[Symbol.iterator]() {
        for (let i = 0; i < this.items.length; i += this.pageSize) {
            yield this.items.slice(i, i + this.pageSize);
        }
    }
}

const pages = new Pagination([1,2,3,4,5,6,7], 3);
for (const page of pages) {
    console.log(page); // [1,2,3], [4,5,6], [7]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 13.2.2 Symbol.asyncIterator

定义异步迭代器(详见第12章):

const asyncIterable = {
    async *[Symbol.asyncIterator]() {
        yield await Promise.resolve(1);
        yield await Promise.resolve(2);
        yield await Promise.resolve(3);
    }
};

(async () => {
    for await (const val of asyncIterable) {
        console.log(val); // 1, 2, 3
    }
})();
1
2
3
4
5
6
7
8
9
10
11
12
13

# 13.2.3 Symbol.toPrimitive

控制对象到原始值的转换(在第2章和第3章有基础介绍):

class Temperature {
    constructor(celsius) {
        this.celsius = celsius;
    }
    
    [Symbol.toPrimitive](hint) {
        switch (hint) {
            case 'number':
                return this.celsius;
            case 'string':
                return `${this.celsius}°C`;
            case 'default':
                return this.celsius;
        }
    }
}

const t = new Temperature(36.6);
console.log(+t);          // 36.6(hint: 'number')
console.log(`${t}`);      // '36.6°C'(hint: 'string')
console.log(t + 0);       // 36.6(hint: 'default')
console.log(t > 35);      // true(hint: 'number')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 13.2.4 Symbol.hasInstance

自定义 instanceof 的行为:

class EvenNumber {
    static [Symbol.hasInstance](num) {
        return typeof num === 'number' && num % 2 === 0;
    }
}

console.log(2 instanceof EvenNumber);  // true
console.log(3 instanceof EvenNumber);  // false
console.log(4 instanceof EvenNumber);  // true

// 实际应用:接口检查
class Serializable {
    static [Symbol.hasInstance](instance) {
        return typeof instance.toJSON === 'function';
    }
}

const obj = { toJSON() { return {}; } };
console.log(obj instanceof Serializable); // true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 13.2.5 Symbol.species

控制派生对象的构造函数。当内置方法(如 map、filter)需要创建新实例时,使用 Symbol.species 指定的构造函数:

class MyArray extends Array {
    static get [Symbol.species]() {
        return Array; // 派生方法返回普通 Array
    }
}

const myArr = new MyArray(1, 2, 3);
const mapped = myArr.map(x => x * 2);

console.log(myArr instanceof MyArray); // true
console.log(mapped instanceof MyArray); // false(因为 species 指向 Array)
console.log(mapped instanceof Array);   // true
1
2
3
4
5
6
7
8
9
10
11
12

# 13.2.6 Symbol.toStringTag

自定义 Object.prototype.toString() 的标签:

class MyClass {
    get [Symbol.toStringTag]() {
        return 'MyClass';
    }
}

const obj = new MyClass();
console.log(Object.prototype.toString.call(obj)); // '[object MyClass]'

// 内置对象的 toStringTag
Object.prototype.toString.call(new Map());     // '[object Map]'
Object.prototype.toString.call(new Set());     // '[object Set]'
Object.prototype.toString.call(new Promise(() => {})); // '[object Promise]'
1
2
3
4
5
6
7
8
9
10
11
12
13

# 13.2.7 Symbol.isConcatSpreadable

控制 Array.prototype.concat() 是否展开:

// 默认数组会展开
const arr = [1, 2];
console.log([0].concat(arr)); // [0, 1, 2]

// 阻止展开
arr[Symbol.isConcatSpreadable] = false;
console.log([0].concat(arr)); // [0, [1, 2]]

// 让类数组对象可展开
const arrayLike = {
    0: 'a',
    1: 'b',
    length: 2,
    [Symbol.isConcatSpreadable]: true
};
console.log([].concat(arrayLike)); // ['a', 'b']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 13.2.8 其他内置 Symbol

// Symbol.match / Symbol.replace / Symbol.search / Symbol.split
// 自定义字符串方法行为
class Validator {
    constructor(pattern) {
        this.pattern = pattern;
    }
    
    [Symbol.match](str) {
        return str.includes(this.pattern);
    }
}
console.log('hello world'.match(new Validator('world'))); // true

// Symbol.unscopables
// 控制 with 语句中哪些属性被排除(主要用于兼容性)
Array.prototype[Symbol.unscopables];
// { at: true, copyWithin: true, entries: true, ... }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 13.2.9 内置 Symbol 总览

Symbol 用途 触发场景
Symbol.iterator 默认迭代器 for...of、展开、解构
Symbol.asyncIterator 异步迭代器 for await...of
Symbol.toPrimitive 类型转换 算术/字符串/比较运算
Symbol.hasInstance 实例检查 instanceof
Symbol.species 派生构造函数 map/filter/slice 等
Symbol.toStringTag 类型标签 Object.prototype.toString
Symbol.isConcatSpreadable concat 展开 Array.prototype.concat
Symbol.match 字符串匹配 String.prototype.match
Symbol.replace 字符串替换 String.prototype.replace
Symbol.search 字符串搜索 String.prototype.search
Symbol.split 字符串分割 String.prototype.split
Symbol.unscopables with 排除 with 语句
Symbol.dispose 资源清理 using 声明(ES2024)

# 13.3 WeakRef 与 FinalizationRegistry

# 13.3.1 WeakRef(弱引用)

ES2021 引入 WeakRef,创建对对象的弱引用,不阻止垃圾回收:

let target = { data: 'important' };
const weakRef = new WeakRef(target);

// 通过 deref() 访问目标
console.log(weakRef.deref()); // { data: 'important' }

// 移除强引用
target = null;

// 某个时刻 GC 后
// weakRef.deref() 可能返回 undefined
1
2
3
4
5
6
7
8
9
10
11

实际应用:缓存

class WeakCache {
    #cache = new Map();
    
    get(key) {
        const ref = this.#cache.get(key);
        if (ref) {
            const value = ref.deref();
            if (value !== undefined) return value;
            this.#cache.delete(key); // 已被 GC
        }
        return undefined;
    }
    
    set(key, value) {
        this.#cache.set(key, new WeakRef(value));
    }
    
    has(key) {
        return this.get(key) !== undefined;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 13.3.2 FinalizationRegistry(回调清理)

当注册的对象被垃圾回收时触发回调:

const registry = new FinalizationRegistry((heldValue) => {
    console.log(`对象被回收,附带信息: ${heldValue}`);
});

let obj = { name: 'test' };
registry.register(obj, 'obj-metadata'); // 注册对象

obj = null; // 移除强引用
// 当 GC 发生时,回调被触发

// 取消注册
let obj2 = { name: 'test2' };
const token = {};
registry.register(obj2, 'obj2-info', token);
registry.unregister(token); // 取消监听
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

实际应用:自动清理外部资源

class FileHandle {
    static #registry = new FinalizationRegistry(handle => {
        console.log(`Auto-closing file handle: ${handle}`);
        // nativeClose(handle);
    });
    
    #handle;
    
    constructor(path) {
        this.#handle = path; // 模拟打开文件
        FileHandle.#registry.register(this, this.#handle);
    }
    
    close() {
        FileHandle.#registry.unregister(this);
        // nativeClose(this.#handle);
        this.#handle = null;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

注意:WeakRef 和 FinalizationRegistry 的回调时机不确定,不应依赖它们执行关键逻辑。

# 13.4 装饰器(Decorators)

ES2024(Stage 3)引入的装饰器语法,用于声明式地修改类及其成员。

# 13.4.1 类装饰器

function logged(target, context) {
    // context.kind === 'class'
    // context.name === 类名
    
    return class extends target {
        constructor(...args) {
            console.log(`Creating ${context.name} with args:`, args);
            super(...args);
        }
    };
}

@logged
class User {
    constructor(name) {
        this.name = name;
    }
}

new User('Alice');
// Creating User with args: ['Alice']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 13.4.2 方法装饰器

function bound(target, context) {
    // context.kind === 'method'
    const methodName = context.name;
    
    context.addInitializer(function() {
        this[methodName] = this[methodName].bind(this);
    });
}

function deprecated(target, context) {
    return function(...args) {
        console.warn(`${context.name} is deprecated`);
        return target.apply(this, args);
    };
}

class API {
    @bound
    handleClick() {
        console.log(this); // 始终指向实例
    }
    
    @deprecated
    oldMethod() {
        return 'old result';
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 13.4.3 属性装饰器

function validate(min, max) {
    return function(target, context) {
        // context.kind === 'field' 或 'accessor'
        return function(initialValue) {
            if (initialValue < min || initialValue > max) {
                throw new RangeError(`${context.name} must be between ${min} and ${max}`);
            }
            return initialValue;
        };
    };
}

class Config {
    @validate(1, 100)
    retryCount = 3;
    
    @validate(0, 1)
    opacity = 0.8;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 13.4.4 auto-accessor 装饰器

function observable(target, context) {
    // context.kind === 'accessor'
    const { get, set } = target;
    
    return {
        get() {
            console.log(`Getting ${context.name}`);
            return get.call(this);
        },
        set(value) {
            console.log(`Setting ${context.name} to ${value}`);
            set.call(this, value);
        },
        init(initialValue) {
            console.log(`Initializing ${context.name} to ${initialValue}`);
            return initialValue;
        }
    };
}

class Store {
    @observable
    accessor count = 0;
}

const store = new Store();
store.count;     // Getting count
store.count = 5; // Setting count to 5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 13.5 using 声明与显式资源管理

ES2024 引入 using 声明(基于 Symbol.dispose),实现确定性资源清理。

# 13.5.1 同步资源管理

class FileHandle {
    constructor(path) {
        this.path = path;
        this.closed = false;
        console.log(`Opened: ${path}`);
    }
    
    read() {
        if (this.closed) throw new Error('Already closed');
        return 'file content';
    }
    
    [Symbol.dispose]() {
        if (!this.closed) {
            this.closed = true;
            console.log(`Closed: ${this.path}`);
        }
    }
}

// using 声明 - 离开作用域时自动调用 [Symbol.dispose]()
{
    using file = new FileHandle('/tmp/test.txt');
    console.log(file.read());
} // 自动调用 file[Symbol.dispose]()
// 输出: Opened → file content → Closed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 13.5.2 异步资源管理

class DatabaseConnection {
    constructor(url) {
        this.url = url;
    }
    
    async query(sql) {
        return `Result of: ${sql}`;
    }
    
    async [Symbol.asyncDispose]() {
        console.log('Closing database connection...');
        // await this.client.end();
    }
}

async function main() {
    await using db = new DatabaseConnection('postgres://...');
    const result = await db.query('SELECT * FROM users');
    console.log(result);
} // 自动 await db[Symbol.asyncDispose]()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 13.5.3 DisposableStack

// 管理多个资源
{
    using stack = new DisposableStack();
    
    const file1 = stack.use(new FileHandle('/tmp/a.txt'));
    const file2 = stack.use(new FileHandle('/tmp/b.txt'));
    
    // ... 使用 file1 和 file2
} // 按注册的逆序清理:先 file2,后 file1
1
2
3
4
5
6
7
8
9

# 13.6 其他 ES2020-2024 重要特性

# 13.6.1 structuredClone(ES2022)

全局深拷贝函数,支持循环引用和复杂类型:

const original = {
    name: 'Alice',
    date: new Date(),
    nested: { arr: [1, 2, 3] },
    regex: /hello/gi,
    map: new Map([['a', 1]]),
    set: new Set([1, 2, 3]),
};

// 添加循环引用
original.self = original;

const clone = structuredClone(original);

clone.nested.arr.push(4);
console.log(original.nested.arr); // [1, 2, 3](未被影响)
console.log(clone.self === clone); // true(循环引用正确处理)

// 不支持的类型:Function、DOM节点、Symbol属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

对比其他拷贝方式:

方式 深拷贝 循环引用 特殊类型 性能
{...obj} 浅拷贝 不支持 不处理 快
JSON.parse(JSON.stringify()) 深拷贝 报错 丢失 中等
structuredClone() 深拷贝 支持 保留 中等

# 13.6.2 Error cause(ES2022)

错误链,保留原始错误信息:

async function fetchUser(id) {
    try {
        const response = await fetch(`/api/users/${id}`);
        if (!response.ok) {
            throw new Error(`HTTP ${response.status}`);
        }
        return await response.json();
    } catch (error) {
        throw new Error(`Failed to fetch user ${id}`, { cause: error });
    }
}

try {
    await fetchUser(123);
} catch (error) {
    console.log(error.message);       // 'Failed to fetch user 123'
    console.log(error.cause.message); // 'HTTP 404'(原始错误)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 13.6.3 Array 新方法(ES2023)

不修改原数组的变更方法:

const arr = [3, 1, 4, 1, 5];

// toSorted() - 排序(不修改原数组)
const sorted = arr.toSorted();
console.log(arr);    // [3, 1, 4, 1, 5](原数组不变)
console.log(sorted); // [1, 1, 3, 4, 5]

// toReversed() - 反转
const reversed = arr.toReversed();
console.log(reversed); // [5, 1, 4, 1, 3]

// toSpliced() - splice 的不可变版
const spliced = arr.toSpliced(1, 2, 'a', 'b');
console.log(spliced); // [3, 'a', 'b', 1, 5]

// with() - 修改指定索引
const changed = arr.with(0, 99);
console.log(changed); // [99, 1, 4, 1, 5]

// findLast / findLastIndex
[1, 2, 3, 4].findLast(x => x % 2 === 0);      // 4
[1, 2, 3, 4].findLastIndex(x => x % 2 === 0);  // 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 13.6.4 Hashbang 语法(ES2023)

#!/usr/bin/env node
// 允许在文件第一行使用 hashbang 注释
// 用于直接在命令行执行 JS 文件
console.log('Hello from CLI!');
1
2
3
4

# 13.6.5 Promise.withResolvers(ES2024)

// 传统方式
let resolve, reject;
const promise = new Promise((res, rej) => {
    resolve = res;
    reject = rej;
});

// ES2024 简化写法
const { promise: p, resolve: res, reject: rej } = Promise.withResolvers();
// resolve 和 reject 直接可用

// 实际应用
function createDeferred() {
    return Promise.withResolvers();
}

const deferred = createDeferred();
setTimeout(() => deferred.resolve('done'), 1000);
await deferred.promise; // 'done'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 13.6.6 Object.groupBy / Map.groupBy(ES2024)

const people = [
    { name: 'Alice', age: 25 },
    { name: 'Bob', age: 30 },
    { name: 'Charlie', age: 25 },
    { name: 'Diana', age: 30 },
];

// Object.groupBy
const grouped = Object.groupBy(people, p => p.age);
console.log(grouped);
// {
//   25: [{ name: 'Alice', age: 25 }, { name: 'Charlie', age: 25 }],
//   30: [{ name: 'Bob', age: 30 }, { name: 'Diana', age: 30 }]
// }

// Map.groupBy(键可以是对象)
const mapGrouped = Map.groupBy(people, p => p.age);
// Map { 25 => [...], 30 => [...] }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 13.6.7 Top-level await(ES2022)

模块顶层可以直接使用 await,无需包裹在 async 函数中:

// config.mjs
const response = await fetch('/api/config');
export const config = await response.json();

// app.mjs
import { config } from './config.mjs';
// 导入时会等待 config.mjs 的异步操作完成
console.log(config);
1
2
3
4
5
6
7
8

注意:Top-level await 会阻塞该模块和依赖该模块的所有模块的执行,应谨慎使用。

# 13.6.8 正则表达式 v 标志(ES2024)

v 标志替代 u 标志,支持 Unicode 属性集合操作:

// 集合交集(&&)
/[\p{Script=Greek}&&\p{Letter}]/v

// 集合差集(--)
/[\p{Decimal_Number}--[0-9]]/v  // 非 ASCII 数字

// 字符串字面量匹配
/[\q{abc|def}]/v  // 匹配 'abc' 或 'def'
1
2
3
4
5
6
7
8
上次更新: 2026/06/10, 11:13:41
迭代器与生成器
DOM操作

← 迭代器与生成器 DOM操作→

最近更新
01
信号崩溃快速排查
06-15
02
CoreDump破案
06-15
03
perf火焰图实战
06-15
更多文章>
Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式