JS【详解】Map (含Map 和 Object 的区别,Map 的常用 API,Map与Object 的性能对比,Map 的应用场景和不适合的使用场景)

Map 简介

ES6 新增了数据结构 Map,与普通对象 object 类似,也是键值对的集合,特征如下:

  • 有序(将元素添加的先后顺序作为其次序)【object 无序】
  • 键可以是任意数据类型 【object 的键只能是字符串/Symbol】
  • Map是一个纯哈希结构,而Object不是(它拥有自己的内部逻辑)。
  • 键是唯一性的,不存在重复的键值对。(与 object 相同)
  • 因 Map 也是对象类型,所以它也是 Object 实例
js 复制代码
// person_m 是一个Map对象
typeof person_m  // 得到 object
js 复制代码
console.log(person_m instanceof Object); //true

Map 和 Object 的区别

  • Map 有序,Object 无序
  • Map 的键可以是任意数据类型,Object 的键只能是字符串/Symbol
  • Map是一个纯哈希结构,而Object不是(它拥有自己的内部逻辑)。
  • Map 只能通过构造函数的方式创建,Object 可以通过多种方式(字面量、new Object()、Object.create() 等)创建
  • Map本身具有size属性,Object需要使用 keys()、values()等方法获取;
  • Map本身具有可迭代属性,Object不具有;
  • Map会保持数据的插入顺序,Object不会;

Map 的基本操作

new ------ 创建 Map

创建空Map对象

js 复制代码
let blank_m = new Map();
js 复制代码
console.log(blank_m);
// 打印 Map(0) {}

创建含键值对的 Map 对象

js 复制代码
let person_m = new Map([
  ["name", "朝阳"],
  ["age", 35],
]);
js 复制代码
console.log(person_m);
//  打印 Map(2) { 'name' => '朝阳', 'age' => 35 }

创建以对象为键的 Map 对象

js 复制代码
let cp1_boy = {
  name: "朝阳",
};

let cp1_girl = {
  name: "晚霞",
};

let cp2_boy = {
  name: "范闲",
};

let cp2_girl = {
  name: "林婉儿",
};

let cps = new Map([
  [cp1_boy, cp1_girl],
  [cp2_boy, cp2_girl],
]);
js 复制代码
console.log(cps);
// 打印
// Map(2) {
//   { name: '朝阳' } => { name: '晚霞' },
//   { name: '范闲' } => { name: '林婉儿' }
// }

get ------ 读取键的值

js 复制代码
person_m.get("name")

set ------ 新增键值对 / 修改键的值

若不存在目标键则新增,若存在,则修改目标键的值

js 复制代码
person_m.set("gender", "男");

支持链式调用

js 复制代码
person_m.set("age", 40).set("gender", "男");

delete ------ 删除键值对

js 复制代码
person_m.delete("name");

object 删除键的本质是将其键的值设置为 undefined,所以其键其实仍在内存中!

js 复制代码
delete target_obj.name

clear ------ 清空键值对

js 复制代码
person_m.clear()

has ------ 是否存在目标键

返回 true / false

js 复制代码
if (person_m.has("name")) {
}

size ------ 获取键值对的数量

类似数组的 .length

js 复制代码
person_m.size

object 的方法为

js 复制代码
Object.keys(target_obj).length

js 复制代码
Object.getOwnPropertyNames(target_obj).length

遍历 Map

forEach ------------ 留意顺序 value, key

js 复制代码
person_m.forEach((value, key) => {
  console.log(key, value);
})

for of ------------ 留意顺序 key,value (使用了数组解构赋值 [ ] !)

js 复制代码
for(let [key,value] of person_m){
  console.log(key,value);
}

Map 转 数组

bash 复制代码
let arr=[...person_m]

得到

js 复制代码
[ [ 'name', '朝阳' ], [ 'age', 35 ] ]

其他操作

  • 获取所有键 keys()
js 复制代码
for(let key of person_m.keys()){
  console.log(key);
}
  • 获取所有值 values()
js 复制代码
for(let value of person_m.values()){
  console.log(value);
}
  • 获取所有键和属性值 entries()
js 复制代码
for(let [key,value] of person_m.entries()){
  console.log(key,value);
}

Map 的性能(与 Object 对比)

  • 增加键

    量小时差异不大,量大时,Map比object 快,因为 Map内部使用了哈希表,而object在内存分配和处理上开销较大

  • 查找键

    都非常快,但在某些情况下,当查找的键在数据结构中不存在时,Map可能会比 Object 更快。这是因为Map会在内部快速定位到哈希表中的空位,而0bject需要遍历整个原型链。

  • 删除键

    Map 优于 Object 。因为Map的内部实现使得删除操作更加高效。在Object中,删除一个键实际上仅仅是将其值设置为undefined,而不是真正地从内存中移除,这可能导致内存泄漏和性能下降。

  • 遍历

    Map 优于 Object 。Map内部的哈希表结构保证了遍历的顺序与插入顺序相同。而Object在遍历时,可能因为属性的插入顺序和内部哈希结构而导致遍历顺序不一致。此外,Map提供了内置的迭代器,可以使用for...of循环方便地遍历键值对。

Map 的应用场景

关联复杂数据类型的数据

利用 Map 的键可为任意数据类型的特性!

js 复制代码
const employeeProjects = new Map();
employeeProjects.set(employee1, [projectA, projectB]);
employeeProjects.set(employee2, [projectC, projectD]);

// 查找员工参与的项目
console.log(employeeProjects.get(employee1)); // 输出 [projectA, projectB]

Vue3 数据响应式 reactive 和 effect 的源码中,大量使用了 Map

大量键的增删和查找操作

在键的量较大时,Map 对键的增加、删除、查找和遍历性能都比 object 更好。

Map 不适合使用的场景

  • 在需要使用JSON时(因JSON 尚未支持Map,但直接支持Object)
相关推荐
王哲晓42 分钟前
第三十章 章节练习商品列表组件封装
前端·javascript·vue.js
理想不理想v1 小时前
‌Vue 3相比Vue 2的主要改进‌?
前端·javascript·vue.js·面试
酷酷的阿云1 小时前
不用ECharts!从0到1徒手撸一个Vue3柱状图
前端·javascript·vue.js
aPurpleBerry2 小时前
JS常用数组方法 reduce filter find forEach
javascript
ZL不懂前端2 小时前
Content Security Policy (CSP)
前端·javascript·面试
乐闻x2 小时前
ESLint 使用教程(一):从零配置 ESLint
javascript·eslint
我血条子呢3 小时前
[Vue]防止路由重复跳转
前端·javascript·vue.js
半开半落3 小时前
nuxt3安装pinia报错500[vite-node] [ERR_LOAD_URL]问题解决
前端·javascript·vue.js·nuxt
理想不理想v4 小时前
vue经典前端面试题
前端·javascript·vue.js