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)