以下是我学习整理的相关Map笔记!方便以后复习和回顾 嘿嘿~ 如果有哪里错误的或者不合适的欢迎各位看官指正!!鞠躬~
1.1 含义及基本用法
首先哈,在ECMAScript 6 以前,JS对象就实现了用“键 / 值”的方式来存储,也就是使用 对象属性 作为键,再用 属性 来引用值。
看个例子:
js对象,键值对的集合(Hash结构),传统上只把 字符串 当做键!!!另外还有 数值,符号。
const data = {} // 定义一个对象
const oDiv = document.getElementById('box'); // 指向的就是id名<div id = 'box'></div>
data[oDiv] = 'abc'; // 获取 oDiv 作为键 并 赋值
赋完值之后,由于对象只接收 字符串 作为键名!!!
所以oDiv会自动转换:
oDiv ---> '[object HTMLDivElement]' // 转化成字符串
就是因为这个原因,所以它受到了限制,所以为了解决这个问题,就出现了Map。
为了解决此问题,ECMAScript 6 提供了 Map 数据结构,类似于对象,也是键值对的集合。但是,“键”的范围不限于 字符串。(与 Object 只能使用数值,字符串或符号作为键不同,Map 可以使用任何JavaScript数据类型作为键。Map的大多数特性都可以通过Object类型实现,但二者之间还是存在一些细微的差别,具体实践使用哪一个,还需细细甄别)
Map 结构 ,提供了 键值 一 一对应的模式,这样更能够完美的体现 Hash结构 ,如果说你需要一个键值对的数据,那么 Map 肯定要比 Object 更合适!
例子:
<script>
//Map 是一个构造函数
const a = new Map(); // 实例化一个对象
const b = {c:"hello"};
// 用set方法 a.set(把...作为键)
a.set(d,'main'); // 设置d作为a的键
// 用get方法 a.get(获取 某键的值 );
console.log(a.get(d)); // main -- 如果没有,则返回 undefined
</script>
同样,Map 也可以接收一个数组作为参数,成员是一个个表示键值对的数组 (认真看代码)
<script>
// 嵌套数组
const t = new Map ([
['name','唐僧'],
['age','20'],
['sex','男']
]
);
// 一些 Map 方法
实例属性 -- size set
操作方法 -- get has delect clear
console.log(t.size); // 2 -- 获取键值对的数量
console.log(t.has('name')); // true -- has 判断是否存在 返回true / false
console.log(t.get('name')); // 唐僧 -- 查询获取键/值对内容
t.delete('name'); // 删除一个键/值对
console.log(t.has('name')); // false 已删除
t.clear(); // 清除所有的键/值对
那么这个以上流程是怎么来的呢 或者说底层原理是什么呢?
// 比如你定义了一个数组
const t = new Map ([
['name','唐僧'],
['age','20'],
['sex','男']
]
);
const d = new Map(); // 新建一个
// 遍历 键 值
d.forEach(
([key,value]) => d.set(key,value)
)
以上 就是前面Map方法的一些 底层算法逻辑
</script>
事实上,不只有数组,任何具有 iteraror接口,且每个成员都是双元素的数组的数据结构,都可以是Map参数
例 :Set 和 Map 都可以生成新的Map ;
<script>
// 如果使用Set 对象 是啥样
const set1 = new Set([
['str',1],
['num',8]
]);
const s = new Map(set1);
console.log(s.get('str')); // 1
const b = new Map([['bar',4]]); // 不管里面是多少个键值对都要用[]括起来
const c = new Map(b);
console.log(c.get('bar')); // 4
此例子分别用了 Set 和 Map对象 当做Map构造函数的参数,结果都生成了新的 Map对象。
</script>
如果对同一个键名重复赋值,后一次会覆盖前一次的值。
<script>
// set() 方法 返回实例化对象,所以可以把多个操作连缀起来,包括初始化声明:
const a = new Map().set('aa',56);
a.set('a',1).set('a',2).set('c',3).set('b',4);
console.log(a.get('a')); // 2 -- 如果重复给键名赋值,那么后面的会覆盖前面的
</script>
set 和 get 表面是针对同一个键,但是实际上 是两个不同的数组实例,内存地址是不一样的!因此,get 无法读取该键,然后返回undefined
const a = new Map();
a.set(['aa'],200); // 地址不一样
console.log(a.get['aa']); // undefined
1.2 实例方法 和 实例属性
size()获取 键 / 值对 的数量
Map.prototype.set( key , value )
set 方法设置键名key,对应的键值为value,然后返回整个Map结构
如果key 已经有值了,那么键值会被更新 ,否则生成新的键
const a = new Map();
a.set('aa',5); // 键 ,字符串
a.set('bb',6); // 键 ,字符串
a.set(123,'cc'); // 键 ,数值
a.set(undefined,'dd'); // undefined
也可以写作 链式结构:
链式结构:
const a = new Map().set('aa',5).set('bb',6).set(123,'cc').set(undefined,'dd');
Map.prototype.get( key ) 读取key的值,找不到返回 undefined
Map.prototype.has( key ) 返回boolean ,表示键是否存在当前Map中。
Map.prototype.delete( key ) 删除某个键,返回true ,删除失败,返回false
Map.prototype.clear( ) 清除全部 ,没有返回值
遍历方法:
Map.prototype.keys() 返回键名遍历器
Map.prototype.values( ) 返回键值的遍历器
Map.prototype.entries( ) 返回所有键 / 值对的遍历器
Map.prototype.forEach( ) 遍历 Map 的所有键 / 值对
1.3顺序与迭代
与 Object 类型的一个主要差异是,Map 实例会维护键值对的插入顺序,因此可以根据插入顺序执行迭代操作。
实例化可以提供一个迭代器(Iterator),能以插入顺序生成 [ key,value ] 形式的数组。
可以通过 entries()方法 (或者 Symbol.iterator属性,它引用 entries () )取得这个迭代器:
const set1 = new Set([
['key1','val1'],
['key2','val2'],
['key3','val3'],
['key4','val4']
]);
console.log(set1.entries === set1[Symbol.iterator]); // true
for(let p of set1.entries()){
alert(p);
}
// [key1,val1]
// [key2,val2]
// [key3,val3]
// [key4,val4]
for(let p of set1[Symbol.iterator]()){
alert(p);
}
// [key1,val1]
// [key2,val2]
// [key3,val3]
// [key4,val4]
因为 entries 是默认迭代器,所以可以直接对实例化对象使用扩展操作,使其转换为数组:
const set1 = new Set([
['key1','val1'],
['key2','val2'],
['key3','val3'],
['key4','val4']
]);
console.log([...set1]);
// [key1,val1],[key2,val2],[key3,val3],[key4,val4]
keys() 和 values()分别返回以插入顺序生成键和值的迭代器
const set1 = new Set([
['key1','val1'],
['key2','val2'],
['key3','val3'],
['key4','val4']
]);
// keys
for(let p of set1.keys()){
alert(p);
}
// key1
// key2
// key3
// key4
// values
for(let p of set1.values()){
alert(p);
}
// val1
// val2
// val3
// val4
然后 , 键和值在迭代器遍历时是可以修改的,但映射内部的引用则无法修改。当然,这并不妨碍修改作为键或值的对象内部的属性,因为这样并不影响它们在映射实例中的身份 详情参考《JavaScript 高级程序设计 第4版》
1.4 选择Object 还是Map
对于多数Web开发者来说,选择Object 还是Map 只是个人偏好问题,影响不大。不过,对于在乎内存和性能的开发者来说,对象和映射之间确实存在显著的差别。
(1)内存占用
Object 和 Map 的工程级实现在不同浏览器存在明显差异,但存储单个键 / 值 对所占用的内存数量都会随着键的数量线性增加。 批量添加或删除,不同的浏览器情况不同,但给定固定大小的内存,Map 大约 可以比 Object 多存储50%的键/值对。
(2)插入性能
消耗大致相当,但是如果代码涉及大量插入操作,明显 Map 的性能更佳。
(3)查找速度
如果代码涉及大量查找操作,那么某些情况下选择 Object 会更好一些。
(4)删除性能
如果代码涉及大量删除操作,毫无疑问应该选择 Map。