JavaScript Map:键值存储与高效查找

JavaScript Map 对象用于存储键值对,并允许任意值(对象、函数、原始值)作为键。需要按插入顺序迭代、使用非字符串键,或频繁新增和删除条目时,应使用 Map。与普通对象不同,Map 的键不会受到继承原型属性影响,这能避免动态字符串键带来的意外冲突。

JavaScript Map 键值存储示例

输出:

输出将显示在这里...

输出:

95
false
2

这个示例如何工作

  1. new Map() 创建一个空映射。直接调用 Map() 而不加 new 会抛出 TypeError
  2. set 添加键值对并返回 Map 实例,因此可以链式调用,例如 map.set("a", 1).set("b", 2)。对已有键再次调用 set 会覆盖值,但不会改变该键在迭代中的位置。
  3. get 返回已存储的值;如果键不存在,返回 undefined。当你要区分“键不存在”和“键存在但值是 undefined”时,使用 has
  4. size 表示当前条目数量;对象则需要 Object.keys(obj).length 才能得到数量。

JavaScript Map 的常见错误

使用方括号语法而不是 set/get

错误写法:

const map = new Map();
map["键"] = "值";
console.log(map.get("键")); // undefined

正确写法:

const map = new Map();
map.set("键", "值");
console.log(map.get("键")); // "值"

方括号语法是在 Map 实例上设置对象属性,而不是设置 Map 条目。gethassize 都不会读取这个属性。

误以为对象键按结构相等比较:

错误写法:

const map = new Map();
map.set({id: 1}, "小李");
console.log(map.get({id: 1})); // undefined

正确写法:

const key = {id: 1};
map.set(key, "小李");
console.log(map.get(key)); // "小李"

Map 使用 SameValueZero 进行键相等比较。对对象来说,这意味着按引用身份比较:两个看起来相同的对象字面量仍然是不同的键。

JavaScript Map 与 Object 对比

MapObject
键类型任意值(对象、函数、原始值)仅字符串和 Symbol
迭代顺序插入顺序(有保证)大多按插入顺序,但类整数键会先排序
大小map.sizeObject.keys(obj).length
原型冲突键可能遮蔽 toStringconstructor
JSON 序列化需手动通过 Object.fromEntries内置 JSON.stringify

当键不是字符串、条目需要频繁增删,或你要存储不受信任的键时,使用 Map。固定结构记录或需要 JSON 序列化的数据,使用普通对象。 如果你需要对象但又想避免原型键冲突,可用 Object.create(null) 作为底层对象。

FAQ

JavaScript Map 会保留插入顺序吗?

会。Map 会按键首次插入的顺序迭代条目。对已有键调用 set() 只会更新值,不会改变原位置。删除后再添加同一个键,会把它放到末尾。

JavaScript Map 可以使用对象作为键吗?

可以,但 Map 比较对象键时看的是引用而不是结构。属性完全相同的两个不同对象会被当成两个键。把对象引用保存到变量里,并在 setget 中使用同一个引用。

如何把 JavaScript Map 转成对象或 JSON?

调用 Object.fromEntries(map) 可以创建普通对象,但前提是所有键都是字符串或 Symbol。若有非字符串键,先序列化条目数组:JSON.stringify([...map])

JavaScript Map 和 JavaScript map() 函数有什么区别?

Map 是用于存取数据的键值集合。JavaScript map() 函数(Array.prototype.map)是数组方法,会对每个元素应用回调并返回新数组。两者同名,但用途完全不同。