# Map
# Map是什么
Map 是 ECMAScript 6 (ES6
) 引入的一种新的数据结构。
它类似于对象,也是键值对的集合,但是使用上更加灵活和强大。
Map 允许任何类型的值(包括对象)作为键或值。
// 创建一个新的 Map
let myMap = new Map();
// 添加键值对
myMap.set('name', '张三');
myMap.set(1, 'number one');
myMap.set(true, 'boolean');
// 获取值
console.log(myMap.get('name')); // 输出:张三
console.log(myMap.get(1)); // 输出:number one
console.log(myMap.get(true)); // 输出:boolean
# 方法和属性
size | 返回 Map对象中的键值对数量 |
---|---|
set(key, value) | 向 Map中添加或更新一个指定的键值对 |
get(key) | 返回一个指定键的值,如果不存在,则返回 undefined |
has(key) | 返回一个布尔值,表示 Map 中是否存在指定的键 |
delete(key) | 从 Map 中移除指定的键值对 |
clear() | 移除 Map 中的所有键值对 |
keys() | 返回一个包含 Map 中所有键的迭代器 |
values() | 返回一个包含 Map 中所有值的迭代器 |
entries() | 返回一个包含 Map 中所有键值对的迭代器 |
forEach(callbackFn, thisArg) | 对 Map 中的每个键值对执行指定的回调函数 |
# 基本使用举例
let fruits = new Map();
// 使用 set() 添加键值对
fruits.set('apple', 5);
fruits.set('banana', 3);
fruits.set('orange', 2);
console.log(fruits.size); // 输出:3
console.log(fruits.get('banana')); // 输出:3
console.log(fruits.has('grape')); // 输出:false
fruits.delete('orange');
console.log(fruits.size); // 输出:2
// 遍历 Map
fruits.forEach((value, key, map) => {
console.log(key, value);
console.log(map) // fruits 本身
console.log(this) // this Arg document
}, document);
// 使用 for...of 遍历
for (let [fruit, quantity] of fruits) {
console.log(fruit, quantity);
}
fruits.clear();
console.log(fruits.size); // 输出:0
# Map和对象的区别
对象 | Map | |
---|---|---|
键的类型(Key) | 键只能是字符串或 Symbol | 键可以是任何类型,包括函数、对象或任意基本类型 |
键的顺序 | 键没有固定顺序 | 键是有序的。当遍历时,Map 对象以插入的顺序返回键值对 |
大小(Size) | 需要手动计算大小 | 可以通过 size 属性直接获取 |
迭代 | 需要通过其他方法如 Object.keys() 来获取键然后进行迭代 | 是可迭代的,可以直接进行迭代 |
性能 | 在频繁增删键值对的场景下表现一般 | 在频繁增删键值对时表现更好 |
示例对比
// 对象
let obj = {
name: '李四',
1: 'number one',
true: 'boolean'
};
console.log(obj.name); // 输出:李四
console.log(obj['1']); // 输出:number one
console.log(obj.true); // 输出:boolean
// Map
let map = new Map([
['name', '李四'],
[1, 'number one'],
[true, 'boolean']
]);
console.log(map.get('name')); // 输出:李四
console.log(map.get(1)); // 输出:number one
console.log(map.get(true)); // 输出:boolean
// 大小比较
console.log(Object.keys(obj).length); // 手动计算对象大小
console.log(map.size); // 直接获取 Map 大小
// 迭代比较
// 对象迭代
for (let [key, value] of Object.entries(obj)) {
console.log(key, value);
}
// Map 迭代
for (let [key, value] of map) {
console.log(key, value);
}
# 构造函数
Map 的构造函数允许我们在创建 Map 实例时初始化键值对。我们可以传入一个可迭代对象(如数组),其中每个元素都是一个键值对数组。
语法
new Map([iterable])
其中 iterable
是一个数组(或者其他可迭代对象),其元素是键值对(两个元素的数组)。每个键值对会被加到新的 Map 中。
举例
// 使用数组创建 Map
let map1 = new Map([
['key1', 'value1'],
['key2', 'value2']
]);
console.log(map1.get('key1')); // 输出:value1
// 使用另一个 Map 创建新的 Map
let map2 = new Map(map1);
console.log(map2.get('key2')); // 输出:value2
// 创建空 Map
let emptyMap = new Map();
console.log(emptyMap.size); // 输出:0
# 注意事项
- 键的唯一性 Map 中的每个键都必须是唯一的。如果多次使用相同的键设置值,后面的值会覆盖前面的值。
- 键的比较 Map 使用
SameValueZero
算法来比较键的相等性。这意味着NaN
被视为等于NaN
(虽然NaN !== NaN
),而 +0 和 -0 被视为相等。 - 引用类型作为键 当使用对象作为键时,要注意引用相等性。两个看起来相同但分别定义的对象会被视为不同的键。
- 迭代顺序 Map 保持键的插入顺序。在迭代时,键值对会按照插入的顺序返回。
- 性能考虑 对于大量数据或频繁增删操作,Map 通常比普通对象有更好的性能表现。
- 序列化 Map 对象不能直接被
JSON.stringify()
序列化。如需序列化,需要先将 Map 转换为数组或普通对象。
举例
// 引用类型作为键的注意事项
let keyObj1 = {id: 1};
let keyObj2 = {id: 1};
let myMap = new Map();
myMap.set(keyObj1, 'value1');
myMap.set(keyObj2, 'value2');
console.log(myMap.size); // 输出:2,因为 keyObj1 和 keyObj2 是不同的对象引用
// 序列化 Map
let map = new Map([['key1', 'value1'], ['key2', 'value2']]);
let jsonString = JSON.stringify([...map]);
console.log(jsonString); // 输出:[["key1","value1"],["key2","value2"]]
# 总结
Map
适用于需要非字符串类型键、保证插入顺序、频繁增删操作或需要键值对操作的场景。它提供了更强大、灵活的 API 和性能优势,因此在处理复杂键值对数据时是不错的选择。
扫码关注(有广告,介意请勿关注)