Map数据结构详解
Posted 王帆
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Map数据结构详解相关的知识,希望对你有一定的参考价值。
Map
Object
本质上是键值对的集合(Hash结构),但Object
只能将字符串当做键,这就给Object
带来了很大的限制。
let data =
let s =
name : \'东方不败\'
data[s] = \'西方求败\'
// 如果键传入非字符串的值,会自动为字符串
console.log(data); // [object Object]: \'西方求败\'
console.log(data[\'[object Object]\']); // 西方求败
为了解决这个问题,es6
提供了Map
数据结构。它类似于对象,也是键值对集合,但键不局限于字符串
,各种类型的值都可以当做键。
- Object结构:
字符串键:值
- Map结构:
值键:值
let data2 = new Map()
let s2 =
name : "艺术概论"
data2.set(s2,\'中国工艺美术史\')
console.log(data2.get(s2)); // 中国工艺美术史
console.log(data2); // key: name: \'艺术概论\' , value : "中国工艺美术史"
上面案例使用Map
的set
方法,将s2
当做data2
的键,使用get
方法取值。
Map的一些常用方法
方法 | 说明 |
---|---|
set() | 为Map对象添加一个指定键(key)和值(value)的新元素 |
get() | 用来获取Map对象中指定的元素 |
has() | 返回boolean值,用来表明Map中是否存在该元素 |
delete() | 删除对应元素 |
size | 返回Map的成员数 |
clear() | 清除Map所有成员,没有返回值 |
let data2 = new Map()
let s2 =
name : "艺术概论"
data2.set(s2,\'中国工艺美术史\')
data2.size; // 1
data2.has(s2); // treu
data2.delete(s2); // true
data2.has(s2); // false
data2.clear(); // undefined
Map参数
Map
可以接收数组作为参数,数组的成员是单个单个
的键值对的数组
let map = new Map([
[\'name\',\'东方不败\'],
[\'title\',\'西方求败\']
])
console.log(map.size); // 2
console.log(map); // "name" => "东方不败", "title" => "西方求败"
console.log(map.has(\'name\')); // true
console.log(map.get(\'name\')); // 东方不败
注意:如果有多个相同的键,后面的键值会覆盖前面的键值
不仅是数组,任何具有Iterator
接口、且每个成员都是一个双元素的数组
的数据结构,都可以当做Map
构造函数的参数,Set
和Map
也可以用来生成新的Map
Set作为参数
let set = new Set([[\'a\',1],[\'b\',2]])
let m = new Map(set)
console.log(m); // \'a\' => 1, \'b\' => 2
console.log(m.get(\'a\')); // 1
Map作为参数
let map2 = new Map([[\'text\',\'世界现代设计史\'],[\'name\',\'王受之\']])
let m2 = new Map(map2)
console.log(m2); // \'text\' => \'世界现代设计史\', \'name\' => \'王受之\'
console.log(m2.get(\'text\')); // 世界现代设计史
console.log(m2.get(\'hello\')); // 读取不存在的键会返回undefined
Map
只有对同一个对象的引用才视为同一个键
let map3 = new Map()
map3.set([\'a\',100])
console.log(map3.get([\'a\'])); // undefined
因为数组不是引用类型,生成多个数组,它们的内存地址是不一样的,其实就是基础数据类型和引用数据类型的应用,这里的两个[\'a\']
看似是一样的,其实它们根本就是两个不同的值,Map
只有对同一个对象的引用才视为同一个键,没有读取到所以返回undefined
。请看下面的例子
let map4 = new Map()
let b = [\'b\']
let b2 = [\'b\']
map4.set(b)
console.log(map4.get(b2)); // undefined
Map
的值其实是跟内存地址绑定的,内存地址不同,那么键就不同(即使名字一模一样),在这里Map
就解决了同名属性冲突的问题,当我们使用别人的库时,使用对象名当做键,就不同担心自己的属性与别人的属性相同了。
如果Map
的键是一个简单数据类型的值,如:number、string、boolean
,只要这两个值严格相等,Map
就视为同一个键,例如:0
和-0
就是同一个键,而布尔值true
和字符串true
就是不同的键,此外null
和undefined
也是不同的键。NaN
视为同一个键。
let n = new Map()
n.set(0,100)
console.log(n.get(-0)); // 100
n.set(5,123)
console.log(n.get(\'5\')); // undefined
n.set(true,100)
console.log(n.get(1)); // undefined
n.set(NaN,123)
console.log(n.get(NaN)); // 123
n.set(null,100)
console.log(n.get(null)); // 100
console.log(n.get(undefined)); // undefined
Map遍历方法
Map
提供三个遍历器生成函数和一个遍历方法
方法 | 说明 |
---|---|
Map.prototype.keys() | 返回键名的遍历器。 |
Map.prototype.values() | 返回键值的遍历器。 |
Map.prototype.entries() | 返回所有成员的遍历器。 |
Map.prototype.forEach() | 遍历 Map 的所有成员。 |
定义数据
let m3 = new Map([
[\'a\',100],
[\'b\',200],
[\'c\',300]
])
keys
/* keys */
for(let k of m3.keys())
console.log(k); // a b c
values
/* values */
for(let k of m3.values())
console.log(k); // 100 200 300
entries
for(let k of m3.entries())
console.log(k); // [\'a\', 100] [\'b\', 200] [\'c\', 300]
console.log(k[0],k[1]); // a 100 b 200 c 300
// 或
for(let [k,v] of m3.entries())
console.log(k,v); // a 100 b 200 c 300
forEach
m3.forEach(el => console.log(el)) // 100 200 300
m3.forEach((val,index) => console.log(val,index)) // 100 \'a\' 200 \'b\' 300 \'c\'
Map数据结构转换
Map转数组
使用扩展运算符将Map
结构转换为数组
let a = new Map([
[\'a\',1],
[\'b\',2],
[\'c\',3]
])
console.log([...a.keys()]); // [\'a\',\'b\',\'c\']
console.log([...a.values()]); // [1,2,3]
console.log([...a.entries()]); // [\'a\', 1] [\'b\', 2] [\'c\', 3]
console.log([...a]); // [\'a\', 1] [\'b\', 2] [\'c\', 3]
转换后的数组是一个真正的数组,可以使用数组方法
let back = [...a].filter((val,index) => val[1] == 2 )
console.log(back); // [\'b\',2]
数组转Map
let a2 = new Map([
[\'name\',\'东方不败\'],
[num : 3,[\'abc\']]
])
console.log(a2); // 0: "name" => "东方不败" 1: Object => Array(1)
Map转对象
let a3 = new Map()
.set(\'a\',100)
.set(\'b\',200)
/* 通过函数传入map */
function mapToObj(mapVal)
// 在内部创建一个空对象
let obj =
// 遍历map结构,给空对象赋值
for([k,v] of mapVal)
obj[k] = v
return obj
let mObj = mapToObj(a3)
console.log(mObj); // a: 100, b: 200
如果有非字符串键名,会被转换成字符串再创建对象键名
对象转Map
let obj = \'a\':123,\'b\':456
let mObj2 = new Map(Object.entries(obj))
console.log(mObj2); // \'a\' => 123, \'b\' => 456
Map转JSON
Map转JSON需要区分两种情况
1、Map键名都是字符串
2、Map键名有非字符串的情况
1、Map键名都是字符串
可以写一个通用函数,用来将Map转为JSON
let j = new Map()
.set(\'name\',\'东方\')
.set(\'text\',\'不败\')
// mapToObj为上面创建的Map转对象的函数
let shiftStrJson = (mapVal) => JSON.stringify(mapToObj(mapVal))
console.log(shiftStrJson(j)); // \'"name":"东方","text":"不败"\'
2、Map键名有非字符串的情况
function shiftMaptoArrayJson(mapVal)
return JSON.stringify([...mapVal])
let j2 = new Map()
.set(\'name\',\'东方\')
.set(\'text\',\'不败\')
let shiftStrJson2 = shiftMaptoArrayJson(j2)
console.log(shiftStrJson2); // \'[["name","东方"],["text","不败"]]\'
以上两种的转换结果:
JSON转Map
JSON转Map需要区分两种情况
1、Map键名都是字符串
2、Map键名有非字符串的情况
1、键名都是字符串
let strObj = \'"name":"东方","text":"不败"\'
let strMap = new Map(Object.entries(JSON.parse(strObj)))
console.log(strMap); // \'name\' => \'东方\', \'text\' => \'不败\'
2、键名有非字符串情况
let strObj2 = \'[["name","东方"],["text","不败"]]\'
let strMap2 = new Map(JSON.parse(strObj2))
console.log(strMap2); // \'name\' => \'东方\', \'text\' => \'不败\'
案例源码:https://gitee.com/wang_fan_w/es6-science-institute
如果觉得这篇文章对你有帮助,欢迎点亮一下star哟
以上是关于Map数据结构详解的主要内容,如果未能解决你的问题,请参考以下文章