什么是Map
Map是ES6新引入的内置对象,引用MDN对它的介绍
Map对象是键值对的集合。Map中的一个键只能出现一次;它在Map的集合中是独一无二的。Map对象按键值对迭代——一个for...of循环在每次迭代后会返回一个形式为[key,value]的数组。迭代按插入顺序进行,即键值对按set()方法首次插入到集合中的顺序(也就是说,当调用set()时,map 中没有具有相同值的键)进行迭代。
规范要求 map 实现“平均访问时间与集合中的元素数量呈次线性关系”。因此,它可以在内部表示为哈希表(使用 O(1) 查找)、搜索树(使用 O(log(N)) 查找)或任何其他数据结构,只要复杂度小于 O(N)。
Map 与 Obejct 的区别
| Map | Object | |
|---|---|---|
| add | map.set(key, value) | obj[key] = value |
| get | map.get(key) | obj[key] |
| delete | map.delete(key) | delete obj[key] |
| size | map.size | Object.keys(obj).length |
| values | map.values() | Object.values(obj) |
| keys | 任意JavaScript数据类型 | string symbols |
| default keys | 暂无 | JavaScript对象的公共属性 |
| traversal | for...of map.forEach(...) | for...in Object.keys(obj).forEach(...) |
不用在意覆盖默认值
new Map
new Object
JS的设计理念中,对象是一切复杂数据类型的基础,所以创建一个空对象时,会存在大量的基础属性在其原型上,所以在使用时,键值对可能会存在冲突,而Map则不会出现这个情况。
可以使用任意数据类型
Object中只有string和symbol类型的数据,而Map则可以使用任何JS的数据类型,可以帮助我们更好好的处理各种复杂情况。
Map
let obj = { 'a': 'a' };
let func = () => 'hey';
let map = new Map([[123, true], [true, 123], [obj, 'object'], [func, 'function']])
map.keys() // 123, true, Object, () => 'hey'
map.get(obj) // 'object'
map.get(func) // 'function'
map.get({ 'a': 'a' }) // undefined
Object
let obj1 = { 'a': 'a' };
let func = () => 'hey';
let obj = { 123: true, true: 123, obj1: 'object', func: 'function' };
Object.keys(obj)
// ['123', 'true', 'obj1', 'func']
obj[func] //undefined
obj['func'] // 'function'
轻松的遍历它们
Map
使用for...of或forEach
const map = new Map();
map.set(0, 'zero').set(1, 'one');
for (const [key, value] of map) {
console.log(`key: ${key}, value: ${value}`);
}
// key: 0, value: zero
// key: 1, value: one
for (const key of map.keys()) {
console.log(key);
}
// 0
// 1
map.forEach((value, key) => console.log(`key: ${key}, value: ${value}`));
// key: 0, value: zero
// key: 1, value: one
Object
使用for...in或Object.entries().forEach
let obj = { 0: 'zero', 1: 'one' }
for(let key in obj){
console.log(`key: ${key}, value: ${obj[key]}`)
}
// key: 0, value: zero
// key: 1, value: one
Object.entries(obj).forEach((item) => console.log(`key: ${item[0]}, value: ${item[1]}`))
// key: 0, value: zero
// key: 1, value: one
在测试中发现两者的遍历效率,在小数据量下,两者的遍历速度并没有明显差别,但在大数据量下Map的遍历效率会高一些,应该是浏览器引擎进行了特殊处理。
更方便的合并数据
Map
let map = new Map([ [1, 'one'], [2, 'two'] ]);
let arr = [3, 'three']
let combinedMap = new Map(...map, arr);
// { 1 => 'one', 2 => 'two', 3 => 'three' }
let combinedArr = [...map, arr];
// [ [1, 'one'], [2, 'two'], [3, 'three'] ]
Object
let map = new Map([ [1, 'one'], [2, 'two'] ]);
Array.from(map) //[ [1, 'one'], [2, 'two'] ]
const newArr = [...map];
Map与Array是完全兼容的,而且处理起来更加的直观。
获取它们的Size
let map = new Map([1, 'one'], [true, 'true']);
map.size // 2
let obj = { 1: 'one', true: 'true' };
Object.keys(obj).length // 2
Map的缺点
Map没有对JSON的序列化或解析的原生支持
我们可以通过给JSON.stringify(obj, replacer)的replacer参数和传递给JSON.parse(string, reviver)的reviver参数来实现。
function replacer(key, value) {
if(value instanceof Map) {
return {
dataType: 'Map',
value: Array.from(value.entries()),
};
} else {
return value;
}
}
function reviver(key, value) {
if(typeof value === 'object' && value !== null) {
if (value.dataType === 'Map') {
return new Map(value.value);
}
}
return value;
}
使用方法
const originalValue = new Map([['a', 1]]);
const str = JSON.stringify(originalValue, replacer);
const newValue = JSON.parse(str, reviver);
console.log(originalValue, newValue);
对于Object我们可以使用JSON.stringify()和JSON.parse()分别对一个对象进行原生序列化和解析。
尾言
ES6+推广至今,各种新的特性Map Weakmap Set WeakSet Proxy等,早已深入我们的日常开发。但我们还是更加深入了解的这些新特性,通过与旧内容的对比,才能更好的利用它们,提高开发效率。