详解ES6中的Map与Set集合
集合的概念以及和数组的区别
其实数组也是集合,只不过数组的索引是数值类型.当想用非数值类型作为索引时,数组就无法满足需要了.
而Map集合可以保存多个键-值对(key-value), Set集合可以保存多个元素.
对Map和Set一般不会逐一遍历其中的元素.Map一般用来存储需要频繁取用的数据, Set一般用来判断某个值是否存在其中.
ES5中对Map和Set的模拟方法
在ES5中,没有Set和Map集合,一般使用对象来模拟这两种集合,对象的属性作为键(key), 以属性值作为值(value), 即以property:property-value来模拟key-value的形式.具体实现如下:
模拟Map的键值对集合:
//创建一个Map对象 varmap=Object.create(null); //添加属性和属性值,即添加key和value map.key1='value1'; map.key2={}; //取得key对应的value console.log(map.key1);//"value1" console.log(map.key2);//"Object{}"
模拟Set:
//创建一个Set对象 varset=Object.create(null); //添加属性和属性值,即添加key并令其值为true,即表示这个key存在于集合中 set.key=true; //判断key是否存在,然后进行下一步的操作 if(set.key){...}
用对象模拟这两种集合的缺陷
由于对象中的属性名必须是字符串,如果传入的不是字符串则会强制转换成对应的字符串类型
一般使用if语句来判断一个key是否存在于集合中, 当这个key对应的value为false或者可以被强制转换为false时, 则if语句认为这个key不存在.但是其实是存在的,只不过value=false而已.
ES6中的Map和Set集合
下面正式来讨论这两种集合的特点
Map
Map中存储的是key-value形式的键值对, 其中的key和value可以是任何类型的, 即对象也可以作为key.这比用对象来模拟的方式就灵活了很多
Map的创建和初始化
可以用newMap()构造函数来创建一个空的Map
//创建一个空的Map letmap=newMap();
也可以在Map()构造函数中传入一个数组来创建并初始化一个Map.传入的数组是二维数组,其中的每一个子数组都有两个元素, 前者会被作为key, 后者会被作为value, 这样就形成了一个key-value键值对.例如:
//用数组来创建一个非空的Map letarray=[//定义一个二维数组,数组中的每子都有两个元素 ['key1','value1'],//key是字符串"key1",value是字符串"value1" [{},10086],//key是个对象,value是数值10086 [5,{}]//key是个数值类型,value是对象 ]; letmap=newMap(array);//将数组传入Map构造函数中
Map可用的方法
- set(key,value):向其中加入一个键值对
- get(key):若不存在key则返回undefined
- has(key):返回布尔值
- delete(key):删除成功则返回true, 若key不存在或者删除失败会返回false
- clear():将全部元素清除
size属性,属性值为map中键值对的个数
遍历方法forEach()
和数组的forEach方法类似,回调函数中都包含3个参数值,键,和调用这个方法的Map集合本身
map.forEach(function(value,key,ownerMap){ console.log(key,value);//每对键和值 console.log(ownerMap===map);//true });
Set集合
Set和Map最大的区别是只有键key而没有value, 所以一般用来判断某个元素(key)是否存在于其中.
创建和初始化方法,和Map大同小异
既可以创建一个空set也可以用数组来初始化一个非空的set.和Map不同的是,数组是一维数组,每个元素都会成为set的键.例如:
//创建一个数组 letarray=[1,'str'];//一维数组 //用数组来初始化set letset=newSet(array);
set的方法
1、add(key):往set添加一个元素, 如果传入多个参数,则只会把第一个加入进去
letset=newSet(); set.add(1,2,3); console.log(set.has(1),set.has(2),set.has(3));//truefalsefalse可以看到只有第一个参数被加入进了set
2、has(key)
3、delete(key)
4、clear()
遍历方法forEach
和Map的forEach方法相似, 回调函数的参数也是3个(value, key, ownerSet).按道理来说因为set中只有key没有value, 那么会掉函数中不应该存在value这个参数,那么为什么这个value参数仍然存在呢?可能是因为数组和Map的forEach方法的回调函数的参数都是这三个, 如果对于Set而改变了参数,那么就会丢失了一致性.这个理由......
那么既然没有value,那么这个value的值是什么呢?答案是和key一样.我们可以把value和key划等号了.下面这段代码可以验证这个说法.
set.forEach(function(value,key,ownerSet){ console.log(value===key,set===ownerSet);//truetrue });
WeakSet和WeakMap
这两个集合比之前的两个集合在名字之前都加上了Weak, 这个Weak可以直译成弱, 这个弱指的是弱引用, 那么前面不带Weak的Set和Map就不弱,就是强了, 这个强指的是强引用.
与Set和Map的区别
先说表层的区别:
- 弱版本集合的key只能是对象, 对于value的类型没有限制.
- 弱版本集合没有forEach方法,也没有forin方法, 也不能用数组来初始化(会报错).
- 弱版本可用的方法较少.WeakSet只有add,has,delete方法可用;WeakMap只有set,has,get,delete方法可用.
根本区别
弱版本的集合和它们对应的强版本根本的区别在对于对象的引用的强弱上, 而对象指的是key位置的对象,即以对象为key的情况.
强弱版本对于key是对象时的引用机制如下:
将对象设置为key时,就在集合中保存了这个对象的引用.当这个对象没有其他引用了的时候,即只有集合还引用着这个对象的时候,弱类型的集合会放弃对这个对象的引用,把这个对象从集合里移除,不让它继续存在于集合中了,有些“赶尽杀绝”的意思;但是强类型的集合还会一直保存着对这个对象的引用,就把它一直放在集合里.这就是[WeakSet和WeakMap]与[Set和Map]的根本区别.
要注意的是这个机制只作用于key,而value位置绑定的对象无论是否还存在别的引用,WeakMap都不会放弃这个对象.只有这个位置的key绑定的对象没有其他引用时,才会把key和value都放弃.决定权在于key位置.
弱版本集合的主要用处
若版本集合可以用在需要生命周期管理的地方,例如保存对一个DOM对象的引用,如果一个DOM对象使用完毕,没有其他的引用了,那么它应该被垃圾回收,以免产生内存泄漏,那么弱版本的集合就最适合用来保存这样的对象了。
注意:四种集合都是有序的,即元素被添加进去的顺序就是在内部保存的顺序.对于用数组来初始化的集合也一样,按照在数组中的位置依次添加进集合中.
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。