Map
Map 是一种新的集合类型,它为 JS 带来了真正的键/值存储机制。作为ECMAScript 6 的新特性,它与 Object 之间又会有哪些区别呢?
本文将会为您讲述 Map 的基本API ,迭代,开发场景优势等。
1.基本API:get(), has(), delete(), clear()
// 使用 new 关键字和 Map 构造函数创建一个空映射
const why = new Map();
// set() 方法返回映射实例
why.set('cat', 'white').set('dog', 'yellow').set('pig', 'pink');
// 使用 get() 和 has() 方法进行查询
console.log(why.has('cat')); //true
console.log(why.has('snake')); //false
console.log(why.get('cat')); //white
console.log(why.get('snake')); //undefined
// 值得一提的是,get(), has(), delete() 的参数都是键/值对中的键。
// 使用 delete(), 和clear()
why.delete('cat')
console.log(why.has('cat')); //false
console.log(why.get('cat')); //undefined
console.log(why.size) //2
why.clear()
console.log(why.size) //0
2.Map的特别之处在于:Map可以使用任何 JS 数据类型作为键
而Object只能使用数值,字符串或者符号作为键
// 使用new关键字和Map构造函数创建一个空映射
const why = new Map();
const functionKey = function () { };
const symbolKey = Symbol();
const objectKey = new Object();
// 将函数,Symbol和对象作为键
why.set(functionKey, 'functionCat');
why.set(symbolKey, 'symbolCat');
why.set(objectKey, 'objectCat');
why.set(1, '1Cat');
console.log(why.get(functionKey)) //functionCat
console.log(why.get(symbolKey)) //symbolCat
console.log(why.get(objectKey)) //objectCat
console.log(why.get(1)) //1Cat
3.Map的迭代
Map 实例会维护键/值对的插入顺序 ,所以迭代操作可以根据插入的顺序
在 Map 实例中会提供一个迭代器(Interator),能够以插入的顺序生成 [key,value] 的数组。
Map 提供了一个属性和一个方法来取得迭代器,entries() 方法和 Symbol.iterator属性
// 使用new关键字和Map构造函数创建一个空映射
const why = new Map([
['cat', 'white'],
['dog', 'yellow'],
['pig', 'pink']
]);
console.log(why.keys()); //[cat,dog,pig]
console.log(why.values()); //[white,yellow,pink]
for (let m of why.entries()) {
console.log(m); //遍历得到数组的每一个键/值对
}
4.迭代时的修改
键和值在迭代器遍历的时候是可以修改的,但在映射内部的引用是无法修改的。
- 遍历中修改键
const why = new Map().set('cat', 'white');
for (let key of why.keys()) {
key = "dog";
console.log(key); //dog
console.log(why.get('dog')); //undefined
console.log(why.get('cat')); //white
}
- 遍历中修改值
const why = new Map().set('cat', 'white');
for (let value of why.values()) {
value = "black";
console.log(value); //black
console.log(why.get('cat')); //white
}
- 当Map实例是一个对象时,是可以修改该对象的属性,且对象在映射内部仍然引用相同的值
const cat = { age: 1 }
const why = new Map([
[cat, 'white'],
])
for (let key of why.keys()) {
key.age = 100;
console.log(key); //{ age: 100 }
console.log(why.get(cat)); // white
}
console.log(cat); //{ age: 100 }
5.Object 与Map 的开发场景比较
- 内存占用 批量添加或者删除键/值对取决于各个浏览器对该类型内存分配的工程实现,不同的浏览器情况不同。但是存储单个键/值对所占用的内存数量都会随键的数量线性增加。但是若给定大小的内存,Map 大约可以比 Object 多存储50%的键/值对
- 插入性能 插入Map在所有的浏览器中一般会比插入 Object 稍微快点,若涉及大量插入工作,Map性能更好
- 查找速度 从大型 Object 和 Map 中查找键值对的性能差异非常的小,但是当只包含少量键值对,则Object有时候更快。在把 Object当成数组使用的情况下,浏览器引擎可以优化,在内存中使用更高效的布局,这对 Map 无法实现。如果代码涉及大量的查找操作,选择 Object 更好一些。
- 删除性能 Object 使用 delete 的删除性能一直饱受诟病,为此,出现了伪删除对象属性的操作,例如把属性值设置为 undefined 或者 null。但是这是一种令人讨厌的或者是不适宜的折中。对于大多数浏览器引擎,Map的delete()操作比插入和查找更快。如果涉及大量删除操作,应使用Map