当前位置: 首页 > 工具软件 > jquery.map > 使用案例 >

JS中的 Map

羊新翰
2023-12-01

以下是我学习整理的相关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。

 类似资料: