160米标准体重是多少(33.JavaScript映射与集合(Map、Set)数据类型基础知识介绍与使用)
映射与集合(Map 、Set)
前文的学习过程中 ,我们已经了解了非常多的数据类型 ,包括基础类型 、复杂的对象 、顺序存储的数组等 。为了更好的应对现实生产中的情况 ,我们还需要学习更多的数据类型:映射(Map)和集合(Set) 。
映射(Map)
Map是一个键值对构成的集合 ,和对象非常相似 ,都是由一个名称对应一个值组成的 。Map和对象区别在于 ,Map的键可以采用任何类型的数据 ,而对象只能使用字符串作为属性名称 。
Map常用的方法
new Map()——创建Map对象; map.set(key, val)——添加一个键值对; map.get(key)——通过键找到val值 ,如果不存在key ,返回undefined; map.has(key)——判断map是否存在键key ,存在返回true ,不存在返回false; map.delete(key)——删除指定键; map.clear()——清空map中所有的内容; map.size——map中键值对的数量;举个例子:
let map = new Map()//创建一个空的Map map.set(name,xiaoming) //字符串作为键 map.set(3120181049,ID) //数字作为键 map.set(true,Bool) //bool作为键 console.log(map.get(name))//xiaoming console.log(map.has(true)) //true console.log(map.delete(true))//删除true键 console.log(map.size) //2 console.log(map.clear()) //清空 console.log(map.size) //0代码执行结果:
map.set(key, val)方法返回map本身 。
不要使用map[key]访问属性
虽然map[key]方式同样可以访问映射的键值对 ,但是不推荐使用这种方式,因为它会造成歧义 。我们可以看下面的案例:
let map = new Map() map[123] = 123 //创建一个键值对 console.log(map[123])//123 console.log(map[123])这里就出现了一个奇怪的结果:
不仅使用键123还可以使用123访问数据 。
甚至 ,如果我们使用map.set()和map[]混用的方式 ,会引起程序错误 。
在JavaScript中,如果我们对映射使用了map[key]=val的方式 ,引擎就会把map视为plain object ,它暗含了对应所有相应的限制(仅支持String 、Symbol键) 。
所以 ,我们不要使用map[key]的方式访问Map的属性!!
对象作为Map的键
由于Map对键的类型不做任何限制 ,我们还可以把对象当作键值使用:
let clazz = {className:9年1班} let school = new Map() school.set(clazz,{stu1:xiaoming,stu2:xiaohong}) console.log(school.get(clazz))代码执行结果:
在对象中 ,对象是不能作为属性名称存在的 ,如果我们把对象作为属性名 ,也会发生奇怪的事:
let obj = {} let objKey = {key:key} obj[objKey] = haihaihai console.log(obj[[object Object]])代码执行结果:
发生这种现象的原因也非常简单 ,对象会把非字符串 、Symbol类型的属性名转为字符串类型 ,对象相应的就转为[object Object]了 ,于是对象中就出现了一个名为[object Object]的属性 。
Map键值比较方法
Map使用SameValueZero算法比较键值是否相等 ,和===差不多 ,但是NaN和NaN是相等的,所以NaN也可以作为键使用!
链式调用
由于map.set返回值是map本身 ,我们可以使用如下调用方式:
map.set(1,1) .set(2,2) .set(3,3)Map的遍历与迭代
我们可以在以下三个函数的帮助下完成映射的迭代:
map.keys()——返回map所有键的可迭代对象; map.values()——返回map所有值的可迭代对象; map.entries()——返回map所有键值对的可迭代对象;举个栗子:
let map = new Map([ [key1,1], [key2,2], [key3,3], ]) //遍历所有的键 for(let key of map.keys()){ console.log(key) } //遍历所有的值 for(let val of map.values()){ console.log(val) } //遍历所有的键值对 for(let ky of map.entries()){ console.log(ky) }代码执行结果:
遍历的顺序
遍历的顺序和元素插入顺序是相同的 ,这是和对象的区别之一 。
默认的迭代方式实际上,我们很少使用map.entries()方法遍历Map中的键值对 ,因为map.entries()是map的默认遍历方式 ,我们可以直接使用如下代码:
let map = new Map([ [key1,1], [key2,2], [key3,3], ]) for(let kv of map){ console.log(kv) }代码执行结果:
forEach()我们还可以通过Map内置的forEach()方法 ,为每个元素设置一个遍历方法 ,就像遍历数组一样 。
举例如下:
let map = new Map([ [key1,1], [key2,2], [key3,3], ]) map.forEach((val,key,map)=>{ console.log(`${key}-${val}`) })代码执行结果:
从数组 、对象创建Map
可能童鞋们已经发现了 ,在上面的案例中 ,我们使用了一种独特的初始化方式(没有使用set方法):
let map = new Map([ [key1,1], [key2,2], [key3,3], ])我们通过向new Map()传入一个数组 ,完成了快速的映射创建。
我们还可以通过Object.entires(obj)方法将对象转为数组 ,该数组的格式和Map需要的格式完全相同 。
举个例子:
let obj = { xiaoming:heiheihei, xiaohong:hahahahah } let map = new Map(Object.entries(obj)) console.log(map)代码执行结果:
Object.entries(obj)会返回obj对应的数组:[[xiaoming:heiheihei],[xiaoming:hahahahah]] 。
从数组 、Map创建对象
Object.fromEntries()和Object.entries()功能相反 ,可以把数组和Map转为对象。
数组转对象:
let obj = Object.fromEntries([ [key1,val1], [key2,val2], [key3,val3], ]) console.log(obj)代码执行结果:
Map转对象:
let map = new Map() map.set(key1,val1) .set(key2,val2) .set(key3,val3) let obj = Object.fromEntries(map) console.log(obj)代码执行结果:
map.entries()会返回映射对应的键值对数组 ,我们也可以使用一种稍微麻烦的方式:
let obj = Object.fromEntries(map.entries())以上两种方式作用完全相同 ,建议选择更为简短的方式 。
集合(Set)
Set是一系列值的集合(注意没有键) ,我们可以简单的把集合看作一个框,什么值都可以直接扔进去 ,但是每个值都只能出现一次 。
常用的方法:
new Set([iter])——创建一个集合 ,如果传入了一个可迭代变量(例如数组),就使用这个变量初始化集合 set.add(val)——向集合中添加一个元素val set.delete(val)——删除集合中的val set.has(val)——判断集合中是否存在val ,存在返回true ,否则返回false set.clear()——清空集合中所有的元素 set.size——返回集合中元素的数量集合使用案例:
let set = new Set() let xiaoming = {name:xiaoming} let xiaohong = {name:xiaohong} let xiaojunn = {name:xiaojunn} set.add(xiaoming) set.add(xiaohong) set.add(xiaojunn) console.log(set)代码执行结果:
虽然Set的功能很大程度上可以使用Array代替 ,但是如果使用arr.find判断元素是否重复 ,就会造成巨大的性能开销 。
所以我们需要在合适的场景使用合适的数据结构 ,从而保证程序的效率 。
集合迭代
集合的迭代非常简单 ,我们可以使用for...of和forEach两种方式:
let set = new Set([xiaoming,xiaohong,xiaoli])//使用数组初始化集合 for(let val of set){ console.log(val) } set.forEach((val,valAgain,set)=>{ console.log(val) })代码执行结果:
注意 ,使用forEach遍历集合时 ,和map一样有三个参数 ,而且第一个和第二个参数完全相同 。这么做的目的是兼容Map ,我们可以方便的使用集合替换Map而程序不会出错 。
在Map中使用的方法 ,Set同样适用:
set.keys()——返回一个包含所有值的可迭代对象 set.values()——返回值和set.keys()完全相同 set.entries()——返回[val,val]可迭代对象看起啦这些方法有些功能上的重复 ,很奇怪 。实际上,和forEach一样 ,都是为了和Map兼容 。
总结
Map 是一个带键的数据项的集合 。
常用方法:
new Map([iter]) —— 创建 map ,可选择带有 [key,value] 对的 iterable(例如数组)来进行初始化; map.set(key, val) —— 根据键存储值,返回 map 自身 ,可用于链式插入元素; map.get(key) —— 根据键来返回值 ,如果 map 中不存在对应的 key ,则返回 undefined; map.has(key) —— 如果 key 存在则返回 true ,否则返回 false; map.delete(key) —— 删除指定键对应的值 ,如果在调用时 key 存在 ,则返回 true ,否则返回 false; map.clear() —— 清空 map中所有键值对 ; map.size —— 返回键值对个数与普通对象 Object 的不同点主要是任何类型都可以作为键 ,包括对象 、NaN 。
Set —— 是一组值的集合 。
常用方法和属性:
new Set([iter]) —— 创建 set ,可选择带有 iterable(例如数组)来进行初始化 。 set.add(value) —— 添加一个值(如果 value 存在则不做任何修改) ,返回 set 本身。 set.delete(value) —— 删除值 ,如果 value 在这个方法调用的时候存在则返回 true ,否则返回 false 。 set.has(value) —— 如果 value 在 set 中,返回 true ,否则返回 false 。 set.clear() —— 清空 set。 set.size —— 元素的个数 。在 Map 和 Set 中迭代总是按照值插入的顺序进行的 ,所以我们不能说这些集合是无序的,但是我们不能对元素进行重新排序 ,也不能直接按其编号来获取元素 。
创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!