Map() 底层个人理解

137 阅读4分钟

Map 底层个人理解

面试被问了 Map 和一般对象的区别,感觉回答的不好,第二天看了 mdn,进行了一定总结

使用

创建

const newMap = new Map();

增删改查

newMap.set(2, "2"); // 增加2:“2”
newMap.has(3); // false 查找内部是否有含有键为3的键值对
newMap.get(1); // "2"
newMap.delete(1); // 删除2: "2"
newMap.size(); // 0 获取长度
newMap.clear(); // 清空

由于是可迭代属性,可以使用 for of 等方法遍历键值对,是一个数组,第一个参数为 index,第二个是 value

赋值问题

const newMap = new Map();
newMap["3"] = three;

console.log(newMap);
console.log(newMap.get("3"));

这里只有第 1 个方法可以获取到设置的值,为什么这样可以设值?为什么这样设值取不到?

设值

首先,这样可以设值的原因是基于 js 的动态特性
动态类型语言是那些像 JavaScript 语言那样,其解释器在运行时根据变量当时的值分配类型。(选自 MDN)
在 JavaScript 中,Map 对象与普通对象(plain object)有着本质上的不同。当你直接给一个 Map 对象添加属性(如 wrongMap["3"] = "three"),这实际上是利用了 JavaScript 的动态特性,在对象上附加了一个新的属性,而不是操作 Map 内部的数据结构。

但按理来说,这样也可以获取到 Map 的值,毕竟已经实际操作,赋值了,那为什么还是取不到?

取值

Map 内部是有专门的数据结构存储键值对,这些数据结构独立于对象本身的属性系统

这里产生一个新问题,Map 的数据结构是什么?

数据结构

规范要求 map 实现“平均访问时间与集合中的元素数量呈次线性关系”。因此,它可以在内部表示为哈希表(使用 O(1) 查找)、搜索树(使用 O(log(N)) 查找)或任何其他数据结构,只要复杂度小于 O(N)。(选自 MDN)

这里解释了 Map 内部的数据结构,同时也解释了为什么使用 Map 设置对象更适合那些需要频繁增删改查

大多数现代 JavaScript 引擎使用哈希表作为 Map 的底层数据结构。哈希表通过将键转换为一个固定范围内的索引值(称为哈希码),然后将键值对存储在该索引位置上。 这种结构使得查找、插入和删除操作的平均时间复杂度接近 O(1),即非常高效。

那怎么获取到这些 hash 值?

哈希

在大多数 JavaScript 引擎中,Map 对象的键值对是存储在一个内部的哈希表中的。这个哈希表与对象自身的属性系统是分离的。 哈希表通常由 JavaScript 引擎实现,位于内存中的一个特定区域,专门用于高效地存储和检索键值对。每个键通过某种哈希算法转换成一个索引值,然后根据该索引值将键值对存入哈希表。

在 JavaScript 中,Map 对象的内部哈希表是由 JavaScript 引擎实现并管理的,开发者无法直接访问或操作这个内部数据结构。这种设计是为了确保引擎能够高效地管理内存和执行垃圾回收等任务,同时也保证了 API 的一致性和安全性。

为什么不能直接访问? 抽象层次:JavaScript 的设计理念之一是提供高层次的抽象,隐藏底层实现细节。这样做的好处是可以简化编程模型,并允许引擎优化其内部实现而不影响现有代码。 封装性:通过封装,JavaScript 引擎可以自由选择最合适的内部数据结构和算法来实现 Map 的功能,而无需暴露这些细节给开发者。这使得引擎可以在不同版本或平台上进行优化,而不会破坏现有的应用程序。 安全性和一致性:如果允许直接访问内部哈希表,可能会导致不一致的状态或安全隐患。例如,错误地修改哈希表可能导致内存泄漏或其他难以调试的问题。

以上就是看了mdn和查资料后的一点想法,佬们多指导