Skip to content

Map

[TOC]

索引

构造方法

  • new Map()(iterable?),用于创建一个新的 Map 对象的构造函数。暂时没有字面量创建方式

方法

  • map.set()(key, value)修改原集合,用于添加或更新键值对
  • map.get()(key),用于根据键获取对应的值
  • map.has()(key),用于检查指定键是否存在于 Map 中
  • map.delete()(key)修改原集合,用于从 Map 中删除指定的键值对
  • map.clear()()修改原集合,用于完全清空 Map 中的所有键值对。
  • map.forEach()(callbackFn, thisArg?),用于按插入顺序遍历 Map 的所有键值对并执行回调函数。

Map

构造方法

new Map()@

new Map()(iterable?),用于创建一个新的 Map 对象的构造函数。暂时没有字面量创建方式

  • iterable?Iterator,接受一个包含键值对数组的迭代器(如数组、Set、Map 等)。
  • 返回:
  • mapMap,返回一个新的 Map 对象;不传参数返回一个空 Map。

核心特性

  1. 可迭代对象的详细要求

    • 必须提供 二元数组(长度为 2 的数组) 的集合
    • 每个子数组格式:[key, value]
    js
    const validMap = new Map([
      [new Date(), '日志'],
      [document.body, 'DOM 节点'],
      [10n, 'BigInt 键']
    ]);
  2. 键值对初始化规则

    • 键唯一性:重复键会覆盖前值

      js
      const map = new Map([
        ['name', 'Alice'],
        ['name', 'Bob'] // 覆盖 'Alice'
      ]);
      console.log(map.get('name')); // 'Bob'
    • 键类型自由:支持任意类型(对象、函数等)

      js
      const objKey = {};
      const map = new Map([
        [objKey, '对象键'],
        [function() {}, '函数键'],
        [new Date(), '日期键']
      ]);
    • 引用类型键:内容相同的不同对象视为不同键

      js
      const map = new Map([
        [{id: 1}, 'A'],
        [{id: 1}, 'B'] // 两个独立对象,不会覆盖
      ]);
      console.log(map.size); // 2

方法

set()@

map.set()(key, value)修改原集合,用于添加或更新键值对

  • keyany,键值对的。可以是原始值、对象、函数、NaN 等任何 JS 类型。

  • valueany,与键关联的。允许 undefined/null 等所有类型。

  • 返回:

  • mapMap,返回更新后的 Map 对象本身,支持链式调用

核心特性

  1. 添加新键值对

    当键不存在时,添加新条目:

    js
    const map = new Map();
    map.set('name', 'Alice'); // 添加新条目
    console.log(map.size); // 1
  2. 更新现有值

    当键已存在时,更新其值:

    js
    map.set('name', 'Bob'); // 更新值
    console.log(map.get('name')); // 'Bob'
  3. 键比较规则:使用 "SameValueZero" 算法:

    • NaN 被视为相同键(尽管 NaN !== NaN

      js
      map.set(NaN, 'First');
      map.set(NaN, 'Override'); // 覆盖前值
      console.log(map.get(NaN)); // 'Override'
    • 引用类型按内存地址区分:

      js
      map.set({}, 'A');
      map.set({}, 'B'); // 不同对象,新增条目
      console.log(map.size); // 2
  4. 链式调用

    利用返回值实现连续操作:

    js
    const map = new Map();
    map.set('a', 1)
       .set('b', 2)  // 链式调用
       .set('c', 3);
    
    console.log(map.size); // 3
  5. Map 作为自身键

    允许但不推荐,易导致递归问题。

    js
    map.set(map, '自引用键');
    console.log(map.get(map)); // '自引用键'

示例

  1. 基本使用

    js
    const configMap = new Map();
    
    // 1. 添加配置
    configMap.set('theme', 'dark')
             .set('fontSize', 16)
             .set('notifications', true);
    
    // 2. 更新配置
    configMap.set('theme', 'light');
    
    // 3. 使用对象键
    const user = { id: 123 };
    configMap.set(user, { permissions: ['read', 'write'] });
    
    // 4. 获取值
    console.log(configMap.get('fontSize')); // 16
    console.log(configMap.get(user).permissions); // ['read','write']
    
    // 5. 遍历
    configMap.forEach((value, key) => {
      console.log(`${String(key)}: ${JSON.stringify(value)}`);
    });

get()@

map.get()(key),用于根据键获取对应的值

  • keyany,要查找的键。可以是原始值、对象、函数、NaN 等任何 JS 类型。

  • 返回:

  • valueany|undefined,键存在返回对应的值;键不存在返回undefined不会抛出错误)。

核心特性

  1. 键查找机制:使用 SameValueZero 算法:

    • NaN 被视为相同的键(即使 NaN !== NaN

      js
      map.set(NaN, '特殊值');
      console.log(map.get(NaN)); // '特殊值'
      console.log(map.get(0/0)); // '特殊值' (0/0 = NaN)
    • -0+0 被视为相同键

      js
      map.set(-0, '零值');
      console.log(map.get(+0)); // '零值'
    • 引用类型按内存地址区分:

      js
      const obj1 = { id: 1 };
      const obj2 = { id: 1 };
      
      map.set(obj1, 'A');
      console.log(map.get(obj1)); // 'A'
      console.log(map.get(obj2)); // undefined(不同对象)

示例

  1. 不同类型原始值键

    js
    const userMap = new Map();
    
    // 添加不同类型键
    userMap.set('name', 'Alice');
    userMap.set(101, { id: 101, role: 'admin' });
    userMap.set(null, '空键值');
    userMap.set(NaN, '非数值');
    
    // 获取值
    console.log(userMap.get('name')); // "Alice"
    console.log(userMap.get(101));    // {id: 101, role: 'admin'}
    console.log(userMap.get(null));   // "空键值"
    console.log(userMap.get(NaN));    // "非数值"
  2. 对象键

    js
    // 对象键示例
    const alice = { name: 'Alice' };
    userMap.set(alice, 'Alice对象');
    
    console.log(userMap.get(alice)); // "Alice对象"
    console.log(userMap.get({ name: 'Alice' })); // undefined(不同对象)
  3. 链式调用

    js
    // 链式调用结合
    const value = userMap
      .set('newKey', '临时值')
      .get('newKey');
      
    console.log(value); // "临时值"
  4. 安全访问

    js
    // 安全访问示例
    const userId = 102;
    const userData = userMap.get(userId) || { role: 'guest' };
    console.log(userData.role); // "guest"(键不存在时使用默认值)

has()

map.has()(key),用于检查指定键是否存在于 Map 中

  • keyany,要检查的键。可以是原始值、对象、函数、NaN 等任何 JS 类型。

  • 返回:

  • hasboolean,返回键是否存在(不会抛出错误)。

核心特性

  1. 键查找机制:使用 SameValueZero 算法:
    • NaN 被视为相同的键(即使 NaN !== NaN
    • -0+0 被视为相同键
    • 引用类型按内存地址区分

示例

  1. 基本使用

    js
    const config = new Map();
    
    // 添加配置项
    config.set('darkMode', true);
    config.set(NaN, '特殊配置');
    config.set(null, '空键配置');
    
    // 对象键示例
    const user = { id: 101 };
    config.set(user, { permissions: ['read'] });
    
    // 检查键是否存在
    console.log(config.has('darkMode'));      // true
    console.log(config.has('lightMode'));     // false
    console.log(config.has(NaN));             // true
    console.log(config.has(null));            // true
    
    // 检查对象键
    console.log(config.has(user));            // true
    console.log(config.has({ id: 101 }));     // false(不同对象)
  2. 安全操作模式

    js
    // 安全操作模式
    function toggleDarkMode(map) {
      if (map.has('darkMode')) {
        const current = map.get('darkMode');
        map.set('darkMode', !current);
      } else {
        map.set('darkMode', false);
      }
    }
  3. 检查前初始化

    js
    // 检查前初始化
    const requiredKeys = ['apiUrl', 'timeout'];
    requiredKeys.forEach(key => {
      if (!config.has(key)) {
        config.set(key, getDefaultValue(key));
      }
    });
  4. 链式操作(结合set)

    js
    // 链式操作(结合set)
    config.has('debug') || config.set('debug', false);

delete()

map.delete()(key)修改原集合,用于从 Map 中删除指定的键值对

  • keyany,要删除的键。

  • 返回:

  • isDeletedboolean,返回是否删除成功,不会抛出错误

核心特性

  1. 键删除机制:使用 SameValueZero 算法匹配键:

    • NaN 被视为相同的键(即使 NaN !== NaN
    • -0+0 被视为相同键
    • 引用类型按内存地址区分
  2. 删除后效果

    • Map 大小变化map.size 立即减少
    • 迭代器更新:后续遍历不再包含该键值对
    • 内存释放:删除引用类型键可能触发垃圾回收
    js
    const map = new Map([
      ['a', 1],
      ['b', 2],
      ['c', 3]
    ]);
    
    console.log(map.size); // 3
    map.delete('b');
    console.log(map.size); // 2
    
    // 遍历验证
    for (let key of map.keys()) {
      console.log(key); // 输出 'a' 和 'c'
    }

示例

  1. 基本使用

    js
    const userRoles = new Map();
    
    // 添加用户角色
    userRoles.set('alice', 'admin');
    userRoles.set('bob', 'editor');
    userRoles.set(NaN, 'guest');
    userRoles.set(null, 'anonymous');
    
    // 对象键示例
    const charlie = { name: 'Charlie' };
    userRoles.set(charlie, 'viewer');
    
    // 删除操作
    console.log(userRoles.delete('alice'));  // true
    console.log(userRoles.delete('eve'));    // false(不存在)
    console.log(userRoles.delete(NaN));      // true
    console.log(userRoles.delete(null));     // true
    console.log(userRoles.delete(charlie));  // true
    console.log(userRoles.delete({ name: 'Charlie' })); // false(不同对象)
  2. 安全删除函数

    删除键之前先判断该键是否存在

    js
    // 安全删除函数
    function safeRemove(map, key) {
      if (map.has(key)) {
        map.delete(key);
        return `已删除 ${key}`;
      }
      return `键 ${key} 不存在`;
    }
  3. 批量遍历删除:不存在也不报错

    js
    // 批量删除
    const keysToRemove = ['inactive1', 'inactive2'];
    keysToRemove.forEach(key => userRoles.delete(key)); // 不存在也不报错

clear()

map.clear()()修改原集合,用于完全清空 Map 中的所有键值对。

核心特性

  1. 完全清空

    移除 Map 中所有键值对:

    js
    const map = new Map([
      ['a', 1],
      ['b', 2],
      ['c', 3]
    ]);
    
    map.clear();
    console.log(map.size); // 0
  2. 触发垃圾回收

    删除键值对后,若键/值无其他引用,可能触发垃圾回收:

    js
    let obj = { data: 'test' };
    const map = new Map([[obj, 'value']]);
    
    map.clear();
    // 此时 { data: 'test' } 可能被垃圾回收
  3. 引用保持:Map 对象引用不变(变量仍指向同一内存地址)。

  4. 迭代器失效:清空后任何现有迭代器(如 keys(), values())将立即失效。

  5. 原型链不受影响:仅清除实例数据,不改变原型方法。

示例

  1. 基本使用

    js
    // 创建 Map
    const configMap = new Map([
      ['theme', 'dark'],
      ['fontSize', 16],
      [Symbol('token'), 'xyz123']
    ]);
    
    console.log(configMap.size); // 3
    
    // 清空 Map
    configMap.clear();
    console.log(configMap.size); // 0
  2. 验证数据清除

    js
    // 验证数据清除
    console.log(configMap.get('theme'));    // undefined
    console.log(configMap.has('fontSize')); // false

forEach()@

map.forEach()(callbackFn, thisArg?),用于按插入顺序遍历 Map 的所有键值对并执行回调函数。

  • callbackFn(value?,key?,map?)=>undefined,为每个键值对执行的函数。

    • value?any,当前键值对的

    • key?any,当前键值对的

    • map?Map,正在遍历的 Map 对象本身。

  • thisArg?any,执行 callbackFn 时用作 this 的值。

核心特性

  1. 遍历顺序

    严格按键值对的插入顺序执行:

    js
    const map = new Map();
    map.set('a', 1);
    map.set('b', 2);
    
    map.forEach((v, k) => console.log(k)); // 输出 'a' 然后 'b'
  2. 遍历范围

    • 包含所有键值对(无论键/值类型)
    • 添加新元素:遍历期间添加的新元素不会被访问
    • 删除已访问元素:已访问过的元素被删除后不影响后续遍历
    • 删除未访问元素:未访问元素被删除后跳过不访问
    js
    const map = new Map([['a', 1], ['b', 2], ['c', 3]]);
    
    map.forEach((v, k) => {
      if (k === 'b') {
        map.delete('c'); // 删除未访问元素 'c'
        map.set('d', 4); // 添加新元素(不会被访问)
      }
      console.log(k, v); 
      // 输出: 
      //   'a' 1
      //   'b' 2 (元素 'c' 被删除不会输出)
    });
  3. 不可中断

    没有内置中断机制(区别于 for...of + break):

    js
    // 无法使用 break/return 中断
    map.forEach((v, k) => {
      if (k === 'stop') return; // ❌ 不会中断遍历
    });
  4. thisArg 参数作用

    js
    const counter = {
      count: 0,
      increment() {
        this.count++;
      }
    };
    
    map.forEach(function() {
      this.increment(); // this 指向 counter
    }, counter);

示例

  1. 基本使用

    js
    // 基本遍历
    const userMap = new Map([
      ['id', 101],
      ['name', 'Alice'],
      ['email', 'alice@example.com']
    ]);
    
    userMap.forEach((value, key) => {
      console.log(`${key}: ${value}`);
    });
    // 输出:
    //   id: 101
    //   name: Alice
    //   email: alice@example.com