Map的概念
JS的对象只能以字符串或是Symbol作为键值,在ES6规范中引入了Map对象保存键值对,任何值(对象或者原始值) 都可以作为一个键或一个值,并且能够记住键的原始插入顺序。
let myMap = new Map(); // 初始化一个空Map
let myMap = new Map([['张三', 1], ['李四', 2]]); // 初始值
优点
- 一个
Map
的键可以是任意值,包括函数、对象或任意基本类型 Map
中的 key 是有序的。因此,当迭代的时候,一个Map
对象以插入的顺序返回键值Map
的键值对个数可以轻易地通过size属性获取Map
是 iterable 的,所以可以直接被迭代- 在频繁增删键值对的场景下表现更好
方法
size
//返回 一个Map 对象的成员数量
myMap.size; // 2
get
// myMap.get(key);
// 返回某个Map对象中的一个指定元素,键不存在时返回undefined
myMap.get('张三'); // 1
set
// myMap.set(key, value);
// 添加新的键值对,返回Map对象本身
myMap.set('张三', 18);
// 键已存在时会被覆盖
myMap.set('张三', 30);
myMap.get('张三'); // 30
// 因为Set()方法返回Map对象本身,可以使用链式写法
myMap.set('李四', 19).set("王五", 20);
has
// myMap.has(key);
// 返回一个bool值,用来表明map 中是否存在指定元素
myMap.has('张三'); // true
myMap.has('乌兹'); // false
clear
// myMap.clear();
// 移除Map对象中的所有元素,返回undefined
myMap.clear();
delete
// myMap.delete(key);
// 移除 Map 对象中指定的元素, 如果 Map 对象中存在该元素,则移除它并返回 true;否则如果该元素不存在则返回 false
myMap.set('wuzi', 'RNG');
myMap.delete('wuzi'); // true
myMap.has('wuzi'); // false
forEach
// myMap.forEach(callback[, thisArg])
// callback 必要,每个元素所要执行的函数, callback包含三个参数,value - 元素的值,key - 元素的键,Map - 当前正在被遍历的对象
// thisArg 可选,callback 执行时其 this 的值
let myMap = new Map([["foo", 3], ["bar", {}], ["baz", undefined]]);
function logMapElements(value, key, map) {
console.log("m[" + key + "] = " + value);
}
myMap.forEach(logMapElements);
// or
myMap.forEach((value, key, map)=>{
console.log("m[" + key + "] = " + value);
})
// logs:
// "m[foo] = 3"
// "m[bar] = [object Object]"
// "m[baz] = undefined"
forEach
函数处理的元素的范围为第一次执行 callback 函数时 Map 对象中的键值对集合。在 Map
对象调用 forEach
之后加入的元素将不会被调用 callback
函数。如果在调用 forEach
之后 Map
对象中的被改变或者删除了,它们传给 callback
函数的值将会变成 forEach
函数访问它们时的值;callback
不会访问其调用其间被删除的元素。
entries
// myMap.entries()
// 返回一个新的包含 [key, value] 对的 Iterator 对象,返回的迭代器的迭代顺序与 Map 对象的插入顺序相同
const myMap = new Map([[1, "wuzi"], ["2", "jacky"]]);
const myIterator = myMap.entires();
myIterator.next().value; // [1, "wuzi"]
myIterator.next().value; // ["2", "jacky"]
keys
// myMap.keys()
// 返回一个引用的 Iterator 对象。它包含按照顺序插入 Map 对象中每个元素的key值
const myMap = new Map([[1, "wuzi"], ["2", "jacky"]]);
const myIterator = myMap.keys();
myIterator.next().value; // 1
myIterator.next().value; // "2"
values
// myMap.values()
// 返回一个新的Iterator对象。它包含按顺序插入Map对象中每个元素的value值
@@iterator
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map/@@iterator
// for .. of
myMap.set(0, "zero");
myMap.set(1, "one");
for (let item of myMap) {
console.log(item);
}
// [ 0, zero ]
// [ 1, one ]
for (let [key, value] of myMap) {
console.log(key + " = " + value);
}
// 0 = zero
// 1 = one
只有对同一个对象的引用,Map 结构才将其视为同一个键。这一点要非常小心。
复制、合并、与数组的关系
复制Map
let original = new Map([
[1, 'one']
]);
let clone = new Map(original);
console.log(clone.get(1)); // one
console.log(original === clone); // false. 浅比较 不为同一个对象的引用
合并Map
let first = new Map([
[1, 'one'],
[2, 'two'],
[3, 'three'],
]);
let second = new Map([
[1, 'uno'],
[2, 'dos']
]);
// 合并两个Map对象时,如果有重复的键值,则后面的会覆盖前面的。
// 展开运算符本质上是将Map对象转换成数组。
let merged = new Map([...first, ...second]);
console.log(merged.get(1)); // uno
console.log(merged.get(2)); // dos
console.log(merged.get(3)); // three
Map与数组的关系
let kvArray = [["key1", "value1"], ["key2", "value2"]];
// 使用常规的Map构造函数可以将一个二维键值对数组转换成一个Map对象
let myMap = new Map(kvArray);
myMap.get("key1"); // 返回值为 "value1"
// 使用Array.from函数可以将一个Map对象转换成一个二维键值对数组
console.log(Array.from(myMap)); // 输出和kvArray相同的数组
// 更简洁的方法来做如上同样的事情,使用展开运算符
console.log([...myMap]);
// 或者在键或者值的迭代器上使用Array.from,进而得到只含有键或者值的数组
console.log(Array.from(myMap.keys())); // 输出 ["key1", "key2"]
// 与数组合并
let first = new Map([
[1, 'one'],
[2, 'two'],
[3, 'three'],
]);
let second = new Map([
[1, 'uno'],
[2, 'dos']
]);
// Map对象同数组进行合并时,如果有重复的键值,则后面的会覆盖前面的。
let merged = new Map([...first, ...second, [1, 'eins']]);
console.log(merged.get(1)); // eins
console.log(merged.get(2)); // dos
console.log(merged.get(3)); // three
使用
在做一道简单题时想用map,结果却忘了怎么使用,然后使用对象保存再for..in遍历的方式解决。
小明是个马大哈,某天他到超市买了若干双筷子(n<20),筷子的长度不尽相同,他把全部筷子都放在购物袋里面拿回家,路上不小心漏了一根
请你用程序帮他找出是漏掉的筷子是多长
输入: 剩下的筷子数组,如:1, 2, 3, 2, 1, 3, 2
返回值:漏掉的筷子长度,如上述输入返回:2(当输入的筷子数据异常时返回-1,如:找不到漏掉的筷子)
其实就是找数量为单数的值
function findSingle(arr) {
if (!arr) {
return -1;
}
let myMap = new Map();
arr.forEach(item => {
myMap.set(item, !myMap.has(item)); // 单数为true, 复数为false
})
for (let [key, value] of myMap) {
if (value) {
return key;
}
}
}
// or
function findSingle(arr) {
if (!arr) {
return -1;
}
let myMap = new Map();
arr.forEach(item => {
if(myMap.has(item)) {
myMap.delete(item);
} else {
myMap.set(item, true);
}
})
const myIterator = myMap.keys();
return myIterator.next().value;
}
let arr = [2, 3, 2, 5, 3]
console.log(findSingle(arr)) // 5
WeakMap
Map 中对象也不能被释放,使用WeakMap
https://juejin.im/post/6844903646623186958
来源
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!