首页/文章/八股文

Map 完全指南

2025-03-26
15076 分钟
...

JavaScript 中的 Map 完全指南

引言

在 JavaScript 中,Map 是一种用于存储键值对的数据结构,具有灵活的键类型和丰富的方法。相较于传统的对象(Object),Map 提供了更高效的键值对操作方式,特别适合处理大量数据和需要频繁操作键值对的场景。本文将详细介绍 Map 的创建、常用方法、迭代方式,并探讨它与对象的区别和实际应用场景。

1. 创建 Map

使用 new Map() 来创建一个空的 Map

const map = new Map();

也可以在创建时初始化 Map,传入一个包含键值对的数组:

const map = new Map([
  ["name", "Alice"],
  ["age", 25]
]);
console.log(map);

2. Map 和对象的对比

在学习 Map 的基本操作之前,我们先来看一下 Map 与传统对象的区别。

特性Map对象
键的类型任何类型(字符串、对象、函数等)只能是字符串或符号
插入顺序保持插入顺序不保证插入顺序
键值对数量size 属性手动计算(Object.keys().length
原型链污染有,继承 Object.prototype
适用场景频繁操作键值对,大量数据小规模键值对或需要方法时

通过对比可以看出,Map 在键的类型、插入顺序的保持以及键值对操作的效率上,都有显著的优势。

3. Map 的常用方法

3.1 set(key, value)

用于向 Map 添加一个键值对。如果键已经存在,set 会更新其值。

map.set("name", "Bob");
map.set("age", 30);
console.log(map);
3.2 get(key)

获取指定键的值,如果键不存在,返回 undefined

console.log(map.get("name")); 
console.log(map.get("gender"));
3.3 has(key)

检查 Map 中是否存在指定的键,返回 truefalse

console.log(map.has("name")); 
console.log(map.has("gender"));
3.4 delete(key)

删除指定的键值对,返回 true 如果成功删除,否则返回 false

map.delete("age");
console.log(map);
3.5 clear()

清空 Map,删除所有键值对。

map.clear();
console.log(map);
3.6 size

返回 Map 中键值对的数量。

map.set("name", "Alice");
map.set("age", 25);
console.log(map.size);

4. Map 的迭代方法

Map 支持多种迭代方法,可以轻松遍历其中的键值对。

4.1 forEach(callback)

遍历 Map 中的每一个键值对,callback 函数接受三个参数:值、键、Map 本身。

map.forEach((value, key) => {
  console.log(`${key}: ${value}`);
});
4.2 keys()

返回 Map 中所有键的迭代器(Iterator),可以用 for...of 来遍历。

for (let key of map.keys()) {
  console.log(key);
}
4.3 values()

返回 Map 中所有值的迭代器(Iterator)。

for (let value of map.values()) {
  console.log(value);
}
4.4 entries()

返回 Map 中所有键值对的迭代器,每个键值对会以 [key, value] 的形式返回。

for (let entry of map.entries()) {
  console.log(entry);
}
4.5 使用 for...of 遍历 Map

可以直接用 for...of 遍历 Map,默认会调用 entries() 方法,因此会返回 [key, value] 的数组。

for (let [key, value] of map) {
  console.log(`${key}: ${value}`);
}

5. Map 的应用场景

Map 是一种适合存储键值对的结构,尤其适用于以下场景:

  1. 需要使用非字符串类型的键:对象的键只能是字符串或符号,而 Map 可以使用任意数据类型作为键,比如对象、函数等。

    const objKey = { id: 1 };
    const map = new Map();
    map.set(objKey, "Object as key");
    console.log(map.get(objKey));
  2. 需要频繁操作键值对Map 在键值对的查找、插入、删除操作上比对象性能更好,适合在频繁操作键值对的场景下使用。

  3. 需要保持插入顺序Map 会按照插入的顺序存储键值对,因此在遍历时顺序是固定的,而对象则不保证插入顺序。

  4. 避免原型链污染:对象的键可能会受 Object.prototype 影响,而 Map 没有原型链污染问题,可以安全地存储任意键。

6. 使用 Map 统计字母出现的次数

我们可以通过一个例子来比较使用 Map 和不使用 Map 的差别。假设我们有一个字符串,需要统计其中每个字母出现的次数。Map 非常适合这种键值对存储的场景。

方法 1:不用 Map,使用普通对象
function countLettersWithObject(str) {
  const letterCounts = {}; 

  for (let letter of str) {
    if (letterCounts[letter]) {
      letterCounts[letter]++;
    } else {
      letterCounts[letter] = 1;
    }
  }

  return letterCounts;
}

const result = countLettersWithObject("hello world");
console.log(result);
方法 2:使用 Map
function countLettersWithMap(str) {
  const letterCounts = new Map(); 

  for (let letter of str) {
    if (letterCounts.has(letter)) {
      letterCounts.set(letter, letterCounts.get(letter) + 1);
    } else {
      letterCounts.set(letter, 1);
    }
  }

  return letterCounts;
}

const resultMap = countLettersWithMap("hello world");
console.log(resultMap);

7. WeakMap 简介

WeakMapMap 的一种特殊类型,它的键必须是对象,且是弱引用(即不会阻止对象被垃圾回收)。如果某个对象在其他地方不再被引用,那么即使它是 WeakMap 的键,也会被垃圾回收,这样可以防止内存泄漏。

WeakMap 的特点
  1. 只接受对象作为键,不支持基本类型。
  2. 键是弱引用,不会阻止垃圾回收。
  3. 没有 size 属性、clear 方法和遍历方法(forEachkeysvaluesentries),因此不能遍历 WeakMap
使用场景

WeakMap 通常用于私有属性或私有数据的存储,不希望这些数据影响垃圾回收。它适用于对象间的临时映射关系,且在数据无需遍历的情况下使用。

const weakMap = new WeakMap();
let obj = { id: 1 };

weakMap.set(obj, "some value");
console.log(weakMap.get(obj)); 

obj = null;

总结

Map 是一种强大的键值对数据结构,具有灵活的键类型支持、保持插入顺序、丰富的内置方法等优势,适合存储和操作大量键值对。而 WeakMap 则是一种针对对象键的弱引用 Map,在特定场景中帮助管理内存

如果您觉得这篇文章有帮助,请点个赞吧~

分享文章

相关文章

更多文章 →
八股文2025-10-13
cookie跨域介绍
Cookie 跨域问题详解 在 Web 开发中, Cookie 是最常见的客户端存储机制之一,用于记录用户登录状态、偏好设置、会话信息等。然而,当涉及到 跨域请求 时,Cookie 的行为往往变得复杂,尤其在现代浏览器的安全策略下,跨域 Cookie 的传递和写入都有严格的限制。 本文将从基础概念开始,逐步讲解 Cookie 的跨域机制、SameSite 属性、CORS 配置及常见问题解决方案。 一、Cookie 的基础概念 Cooki...
学习面试
八股文2025-10-09
JavaScript 闭包详解
JavaScript 闭包(Closure)详解 一、什么是闭包 闭包(Closure) 是 JavaScript 中一个非常核心且常被问到的概念。简单来说: 闭包是一个函数,它可以“记住”并访问其定义时所在的词法作用域,即使这个函数在其作用域之外被调用。 换句话说,当一个函数“嵌套”在另一个函数中,并且 内部函数引用了外部函数的变量 时,就形成了闭包。 示例: 虽然 已经执行完毕,但 依然可以访问 中的 。这就是闭包。 二、闭包的形成...
学习面试
八股文2025-10-07
开始性能优化之旅
事件循环机制 一、JavaScript 引擎的本质 核心职责 : 解析 JavaScript 语法 管理变量和内存 执行代码逻辑 不涉及 : 线程管理(Worker除外) I/O 操作 定时器控制 网络请求 常见引擎:V8(Chrome)、SpiderMonkey(Firefox)、JavaScriptCore(Safari) 二、宿主环境的扩展能力 宿主提供的多线程能力 : | 线程类型 | 功能 | 对应 API | | | | |...
学习面试
八股文2025-09-30
前端首屏优化
话说,我在面试的时候,80%的情况下,都会被问到首屏优化问题,烦,恨 TCP Slow Start(慢启动)概念 咱先不说标题的数字哪里来的,先说一个概念,就是TCP的慢启动。 你们想哈,在浏览器和服务器开始建立连接的时候,服务器是并不知道浏览端网络的带宽、拥塞状况。假设你本地的带宽是1M,如果一开始服务器就发送2M的文件,那浏览器压根就不是人类,忍忍或者挤挤就能接收到的,这样就可能会引发丢包和重传。 想想,这个该有什么办法解决这个问题...
学习面试
八股文2025-09-28
Function.prototype和Object.prototype
一道面试题引发的原型链血案,彻底搞懂 Function.prototype 和 Object.prototype 前言 有这样一道题: 目录 问题分析与答案揭晓 让我们先公布正确答案,然后深入分析原因: 为什么 是 而不是 ? 这是因为函数和实例的原型链路径完全不同! 原型链的本质机制 JavaScript中的两条原型链 在JavaScript中,存在两条不同的原型链:       关键理解:F.proto...
学习面试
八股文2025-09-10
让你彻底明白什么是闭包
今天我们来聊一个听起来很高大上,但实际上你可能天天在用(只是不知道它名字)的概念—— 闭包 。 一、一个你肯定写过的闭包 先别管定义,来看这段代码,你是不是再熟悉不过了? 恭喜你!这就是一个经典的闭包!是不是很简单? 二、为什么会有闭包?—— 背包的故事 想象一下,JavaScript 中的函数就像一个小机器人,当它被创建时,会背着一个神奇的 背包 。 这个背包里装着什么呢?装着它 出生时 所在环境的所有变量! 当我们调用 时,返回的那...
学习面试

评论

请登录后发表评论

去登录
加载评论中...

目录