第 4 题:介绍下 Set、Map、WeakSet 和 WeakMap 的区别?
http://es6.ruanyifeng.com/ 看完这个就可以了
- Set是一种叫做集合的数据结构
- Map是一种叫做字典的数据结构
- 应用场景:数据去重和数据存储
Set
- 集合是由一组无序且唯一的项组成的,可以想象成集合是一个既没有重复元素,也没有顺序概念的数组
- ES6提供了新的数据结构Set,类似于数组,但是成员的值都是唯一的,没有重复的值
- Set本身是一个构造函数,用来生成Set数据结构的
属性
- size:返回字典所包含的元素个数
操作方法
- add(value):添加某个值,返回Set结构本身
- delete(value):删除某个值,返回一个布尔值,表示删除是否成功
- has(value): 返回一个布尔值,表示该值是否为Set的成员
- clear():清除所有的成员,无返回值
- size: 返回Set数据结构的数据长度
遍历方法
- keys():返回键名的遍历器
- values(): 返回键值的遍历器
- entries():返回键值对的遍历器
- forEach():使用回调函数遍历每个成员,无返回值
Map 字典 类对象
- 类似于对象,也是键值对的集合,但是键的范围不限于字符串,各种类型的值都可以当作键,是一种更完善的Hash结构实现,如果你需要键值对的数据结构,Map 比 Object更合适
- 集合和字典的区别:
— 共同点:集合,字典可以存储不重复的值
— 不同点:集合是以[值,值]的形式存储元素,字典是以[键,值]的形式存储
属性
- size:返回字典所包含的元素个数
操作方法
- set(key,value):向字典树中添加元素
- get(key):通过键值查找特性的数值并返回
- has(key):如果键值存在字典中返回true,否则false
- delete(key):通过键值从字典树中移除对应的数据
- clear():将找个字段中的所有元素删除
遍历方法
- keys():将字典中包含的所有键名以数组形式返回
- values():将字典中包含的所有数值以数组形式返回
- entries():返回键值对的遍历器
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(27)
我觉得看这篇技术文章也可以
new Set([1,2,3]).length 值应该是undefind 而不是0
为了学习 ES6 里面 Set、Map、WeakSet 和 WeakMap 的知识,懒癌晚期的我第一选择立刻翻阅阮一峰老师的 ES6入门 ,挑选里面的局部内容进行摘抄和理解。
Set
看到这句我们可以基本明白,Set 是 “无重复的值的数组 (Array) ”。
然后我们会发现,Set 居然没有 push 、shift 这类的方法吗?不是说是无重复值的数组吗?
原来,Set 的本质还是一个对象,它并不是数组。我们看一下 Set 的构造函数:
*可迭代对象
这里提到了可迭代对象,很多时候我们只记得可迭代对象一般是能够被
for( ... in ... ){}
进行遍历的对象/值。比较常见的可迭代对象:字符串、数组、对象。按照这种说法,那 Object 岂不是也可以被 Set 作为参数……个屁!并不能。凭啥?我们来看看在 MDN 中的真正的定义:
内置字符串对象,数组,类数组……这些才是在 JS 语言中真正的可迭代对象(说起来字符串本身也是一种类数组哦)。所以刚刚的测试报错,我们就用 DevTools 所理解的伪数组(有 length 属性、且有 splice 方法的对象)来骚操作一下 :
为啥有问题?好好看报错!
cannot read property Symbol(Symbol.iterator)
也就是说,如果你想创建一个可迭代对象,你需要让这个对象(类)拥有一个私有标识:Symbol.iterator 。确切地来说,Set 的构造器要求对象具有的这一私有的标识,本质上要求应该是一个“具有 next 方法、且每次 next 方法会返回一个具有 done 和 value 两个属性的对象”的方法,done 的值为布尔值、为 false 则可以继续执行 next 取下一个值。多说无益,show u my code :
输出结果如图:
关于迭代器的一些知识搜索来源于 David Tang 博客中的 《Iterables and Iterators in JavaScript》 ,原文干货很多,建议 Mark 。
按照这种思路,我们甚至可以写一些坑爹东西忽悠 Set 构造器:
就此打住,我们把重心转移回 Set 上。
刚刚我们看到 Set 可以理解为无序的、无重复子元素的数组,所以 Set 理所应当也具有一些和数组相似的方法:
理解到这里,用 Set 给一些存了基本类型数据的数组去重,就很好理解了。
Map
阮一峰老师在文中有一个特别好的总结,我们摘录下:
粗暴理解下,Map 是一个可以用 “任何值” 作为 **键名 **的 对象 。更严谨地说,不是“任何值”,而是“任何指针”。可以用阮一峰老师的例子说明:
最好玩的是,Map 和 Set 的构造器所传参数是一样的——无参数、或者可迭代对象。
只要基于数组理解 Set , 基于对象理解 Map ,其实他俩在意义和特性上是很好理解的,具体的一些方法和属性可以参考阮一峰老师 ES6入门 上的 这一章节 来具体学习。
WeakSet
顾名思义,WeakSet 是“弱 Set”——弱引用版本的 Set。光是知道这句话是不行的,很多同学在刚接触这个定义的时候会有这种猜想:
然后果不其然,我们会被 pia pia 打脸:
“说好的弱引用呢?”
甚至我们掏出 MDN 会发现一个特别神奇的事情:WeakSet 几乎不兼容各种主流浏览器,只有 Chrome 被标注支持了,甚至 Chrome 也要强调:只有开启实验性 JavaScript 才支持。所以 WeakSet 到底是何许码也?既然明码标价是弱引用,那怎么样才能触发它的这个特性,回收后让 WeakSet 中的相关内容消失?
既然已经走到了这里,我们就一口气把 JavaScript 浏览器端和 WeakSet 相关的内存管理、弱引用等知识都搞清楚。首先我们了解下 JavaScript 里有关变量回收的一些规则(参考文章):
所以我们再修改一下上方的代码。
但是结果却依然不行,如图:
原来,JavaScript 语言中,内存的回收并不是在执行 delete 操作符断开引用后即时触发的,而是根据运行环境的不同、在不同的运行环境下根据不同浏览器的回收机制而异的。比如在 Chrome 中,我们可以在控制台里点击 CollectGarbage 按钮来进行内存回收:
在点击此按钮后,我们再打印上方的 ws 变量:
关于在不同浏览器环境下手动进行内存回收的具体异同,可参考:如何手动触发 JavaScript 垃圾回收行为?
每次都必须使用 delete 一个一个删除属性吗?并不,delete 的意义是“断开引用”,同样的,我们也可以用这种方式来进行清理:
这样我们就彻底搞清楚了:JavaScript 会在执行内存回收时,清除掉 被引用次数为0 的那部分内存;而 WeakSet 是只能储存对象的(或者说只能储存内存指针而非静态值)、并且它对对象的引用将不计入对象的引用次数,当清除对象属性、对应的内存被清理之后,WeakSet 中记录的内存地址上不再有内容,它将自动断开与这条引用的关联 —— 也正因如此,它所储存的内容会受到开发者对其他对象操作的被动影响,所以 WeakSet 在设计上就设计成了没有“长度”、“遍历”概念的特殊弱引用 Set 型。
这样的弱引用,用途上可以开一些脑洞,比如阮一峰老师的例子:
相比 WeakMap,它的应用能力不是特别强,或许这也是它目前没有被广泛支持的原因吧。
WeakMap
理解了迭代器、弱引用、内存回收,对 WeakMap 我们就可以很简单地去理解了:
WeakMap 是一个只能以 对象 作为键名的 Map,同时 WeakMap 上 每个键名对应的引用也是弱引用的。
也就是我们刚刚 WeakSet 的值的那种实验,在 WeakMap 的键名上是依然存在的。比如:
懂得很多道理,却依然过不好这一……呸!既然知道定义了就应该知道怎么用!我们先以阮一峰老师的例子 A 来看:
把 DOM 节点用作它的键名是一个常见场景,对应的可以做各种各样的骚操作。再看阮一峰老师的例子 B :
在这两个例子的基础上,我的理解是:WeakMap 非常擅长去配合 非常态的实例、节点、属性 一同使用,在那些内容被销毁时跟着一起被回收。很多时候我们不得不用一些变量来给这些东西做各种各样的辅助,比如 计数器、状态标识、临时值储存……在这种情况下,我们学习了 WeakMap ,就可以用 WeakMap 来做这个辅助的集中管理。
顺带一提, WeakMap 的浏览器支持性完爆 WeakSet ……
感悟
虽然最初只是想大概知道下这几个 ES6 新出的小老弟是干啥用的,不过顺便就把所有的相关知识都梳理了下。我们已经可以看到这些 ES6 的福利正在逐渐普及,和我一样是万年切图仔的同学们也要适当充实下自己在基础方面的知识,不要只知其然不知其所以然啦~
@sisterAn 差集有问题啊
Map: key可为任何类型的键值对
Set: 取值不重复的集合
Weak-:弱引用,不计入垃圾回收
WeakSet和Set都是构造函数,可以使用new命令创建相应的数据结构,并且值都是唯一的;
WeakSet 与 Set 的区别:
1、WeakSet 的成员只能是对象,而不能是其他类型的值,而 Set 对象的成员可以是任意类型的值;
2、WeakSet 对象中储存的对象值都是被弱引用的,即垃圾回收机制不考虑 WeakSet 对该对象的应用,如果没有其他的变量或属性引用这个对象值,则这个对象将会被垃圾回收掉(不考虑该对象还存在于 WeakSet 中),所以,WeakSet 对象里有多少个成员元素,取决于垃圾回收机制有没有运行,运行前后成员个数可能不一致,遍历结束之后,有的成员可能取不到了(被垃圾回收了);
3、由于以上第二点的原因,es6规定WeakSet不能够被遍历,无法使用keys,values等遍历方法,并且不存在size属性。
Map和WeakMap都是构造函数,用域生成键值对的集合;
Map和WeakMap的区别:
1、WeakMap只接受对象作为键名,不接受其他类型的值作为键名,而Map可以接受任何类型的值作为键名;
2、WeakMap的键名所引用的对象都是弱引用,所以这个对象的其他引用都被清除,垃圾回收机制就会释放这个对象所占用的内存;
3、由于第二点的原因,WeakMap不存在遍历操作,没有size的属性,因为WeakMap的键名是不可预测的,可能在不知道的时间,作为键名的对象就被垃圾回收机制清除;
4、不支持clear方法。
Map 多运用于数据存储,和普通Object键值对不同的是,Map的键可以是任何类型而Object只能是字符串
set和WeakSet
set方法:add,has,delete,clear(可遍历) WeakSet: add,has,delete(不可遍历)
接受的成员不同,WeakSet只接受成员是对象
Map方法:set,get,has,delete,clear,可遍历:keys(),values(),entries(),forEach()
WeakMap方法:set,get,has,delete,不可遍历
WeakMap的键只能是对象(null除外)
英文原文关于Set.Map
Set与WeakSet区别:
Map与WeakMap区别:
弱引用最大的特点就是: 我们有时候需要对对象添加一些数据, 但是又不希望把该引用计入到引用计数影响了GC。
以前非弱引用对象需要我们手动清除引用(xx = null)然后被GC回收, 现在弱引用不需要我们这么做, 只要弱引用指向的对象不再被其他对象引用, 那么弱引用对象就会自动消失
1.Set其实就是类数组对象 , 不是标准的数组,没有下标所以不能使用for 循环,但是能使用forEach for of 循环
2.没有length属性,有size属性
3.方法:add delete has clear
4.主要用去数组去重 方法如下:
也可以结合Array from 方法实现数组去重
弱引用
,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。弱引用
,不计入垃圾回收机制。总结:
内部成员唯一性
键可以为 对象、其他类型
可以Map/forEach/filter
可以[...Set]循环
WeakSet(弱应用)
键只能为对象
垃圾回收机制会回收对象
没有
entries
,size
,keys
,values
等Map
内部成员-键存在唯一性
键可以为 对象、其他类型
可以Map/forEach/filter
可以[...Map]循环
内部成员只能是对象
内部的键值对会随着
引用键的对象
消失而被垃圾回收机制
回收因为随时会被回收,所以不存在长度
size
,从而不存在entries
,values
,keys
等WeakMap和WeakSet 都不会
引用值的对象
消失,而被回收,因为值是被存储进去的。Set结构和Map结构都用过,
WeakSet听都没有听过,这次算学习了
WeakSet与Set结构有两个区别
Set与WeakSet
1、Set对象有size、add、delete、clear、has
2 、WeakSet的成员只能是对象( Iterable 接口的对象,都可以作为 WeakSet 的参数)
3、 垃圾回收机制,如果其他对象不再引用该对象,那么垃圾回收机制会回收改对象的所占用的内存。
WeakSet 没有size属性,没有办法遍历它的成员,它只有add、has、delete三个方法。
Map与MapSet
1、 Map数据结构域不仅仅是数组,任何具有 Iterator 接口、且每个成员都是一个双元素的数组的数据结构
Map的方法有size、set、get、has、delete、clear
2、 WeakMap与Map对象的区别.WeakMap只接受对象作为键名(null除外)
3、WeakMap一是没有遍历操作(即没有keys()、values()和entries()方法),也没有size属性,只有
set、get、has、delete这四个方法
Map 的key 可以为引用类型,也可以为基础数据类型,可以理解为对javascript普通对象的扩展。js普通对象key只能为字符串。
WeakMap的key只能为对象【引用类型】;键名指向的值若没有被引用,垃圾回收机制会自动回收该键值对所占用的内存。 没有.size属性 也没法儿forEach去遍历。 只有4个方法 get()、set()、has()、delete() 。
Set 为非重复元素的集合,Set 集合里面的每一项不能重复,引用类型则是地址不能重复,基础类型则是值不能重复。
WeakSet 的元素只能是对象【引用类型】;元素若没有被其他对象引用,垃圾回收机制会自动回收该对象所占用的内存。 没有.size属性 也没法儿forEach去遍历。只有3个方法add()、delete()、has()。
应该不能说 Set 可以使用 map filter 方法吧,只是 Set 和数组互转很方便,结合数据的 map filter 方法,可以实现很方便的交集、并集、差集。
关于weakMap与weakSet弱引用该如何理解
弱引用是向weakSet/weakMap中添加一个目标对象的引用,但添加是目标对象的引用计数不增加。比较来说:
到这里,由于对象的引用计数为0了,所以weakSet中的那个被add()进去的x、y就自动被回收了。——weakSet/weakMap具备这种机制。
所以weakSet/weakMap没有size这个属性,它不安全。——你刚读了它的值,它自己自动回收了一下,就又变掉了。
如果感兴趣大家可以通过链接去订阅(只想表示很硬核)http://gk.link/a/10fj0
差集错了,应该是
老哥你很喜欢健身吗?
Set不是没有键名,是键名和值相同,const set = new Set() set.add(444) set.keys()可获得键名的Iterator对象,set.forEach可遍历
Set: 1. 成员唯一、无序且不重复 2. [value, value],键值与键名是一致的(或者说只有键值,没有键名)
3. 可以遍历,方法有:add、delete、has
WeakSet: 只能插入对象,否则会报错。弱引用,可以被垃圾回收机制回收。所以适合用来保存DOM节点,不容易造成内存泄漏。不可遍历。方法同Set
Map: 本质上是键值对的集合,类似集合,key不局限于字符串,方法有get、set、has、delete
在 “与其他数据结构的相互转换 的 4.Object 转 Map” 参数名称写错了, 应该是 “obj” 而不是 "map"
Set 实例方法下面遍历方法中使用map、filter那个地方 打印写错了 应该是[2,3,4]和[4]吧
WeakMap 里有一段写成了 WeakSet。
ok,已改正,谢谢 @peakDragonCheung
4 Object 转化为 Map , 其中一行代码 map.set(key, obj[k]) 这里是不是写错了,不是 obj[k],而是obj[key]。
Set 和 Map 主要的应用场景在于 数据重组 和 数据储存
Set 是一种叫做集合的数据结构,Map 是一种叫做字典的数据结构
1. 集合(Set)
ES6 新增的一种新的数据结构,类似于数组,但成员是唯一且无序的,没有重复的值。
Set 本身是一种构造函数,用来生成 Set 数据结构。
举个例子:
Set 对象允许你储存任何类型的唯一值,无论是原始值或者是对象引用。
向 Set 加入值的时候,不会发生类型转换,所以
5
和"5"
是两个不同的值。Set 内部判断两个值是否不同,使用的算法叫做“Same-value-zero equality”,它类似于精确相等运算符(===
),主要的区别是**NaN
等于自身,而精确相等运算符认为NaN
不等于自身。**Set 实例属性
constructor: 构造函数
size:元素数量
Set 实例方法
add(value):新增,相当于 array里的push
delete(value):存在即删除集合中value
has(value):判断集合中是否存在 value
clear():清空集合
Array.from
方法可以将 Set 结构转为数组keys():返回一个包含集合中所有键的迭代器
values():返回一个包含集合中所有值得迭代器
entries():返回一个包含Set对象中所有元素得键值对迭代器
forEach(callbackFn, thisArg):用于对集合成员执行callbackFn操作,如果提供了 thisArg 参数,回调中的this会是这个参数,没有返回值
Set 可默认遍历,默认迭代器生成函数是 values() 方法
所以, Set可以使用 map、filter 方法
因此,Set 很容易实现交集(Intersect)、并集(Union)、差集(Difference)
2. WeakSet
WeakSet 对象允许你将弱引用对象储存在一个集合中
WeakSet 与 Set 的区别:
属性:
constructor:构造函数,任何一个具有 Iterable 接口的对象,都可以作参数
方法:
3. 字典(Map)
集合 与 字典 的区别:
任何具有 Iterator 接口、且每个成员都是一个双元素的数组的数据结构都可以当作
Map
构造函数的参数,例如:如果读取一个未知的键,则返回
undefined
。注意,只有对同一个对象的引用,Map 结构才将其视为同一个键。这一点要非常小心。
上面代码的
set
和get
方法,表面是针对同一个键,但实际上这是两个值,内存地址是不一样的,因此get
方法无法读取该键,返回undefined
。由上可知,Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键。这就解决了同名属性碰撞(clash)的问题,我们扩展别人的库的时候,如果使用对象作为键名,就不用担心自己的属性与原作者的属性同名。
如果 Map 的键是一个简单类型的值(数字、字符串、布尔值),则只要两个值严格相等,Map 将其视为一个键,比如
0
和-0
就是一个键,布尔值true
和字符串true
则是两个不同的键。另外,undefined
和null
也是两个不同的键。虽然NaN
不严格相等于自身,但 Map 将其视为同一个键。Map 的属性及方法
属性:
constructor:构造函数
size:返回字典中所包含的元素个数
操作方法:
遍历方法
Map 结构的默认遍历器接口(
Symbol.iterator
属性),就是entries
方法。Map 结构转为数组结构,比较快速的方法是使用扩展运算符(
...
)。对于 forEach ,看一个例子
在这个例子中, forEach 方法的回调函数的 this,就指向 reporter
与其他数据结构的相互转换
Map 转 Array
Array 转 Map
Map 转 Object
因为 Object 的键名都为字符串,而Map 的键名为对象,所以转换的时候会把非字符串键名转换为字符串键名。
Object 转 Map
Map 转 JSON
JSON 转 Map
4. WeakMap
WeakMap 对象是一组键值对的集合,其中的键是弱引用对象,而值可以是任意。
注意,WeakMap 弱引用的只是键名,而不是键值。键值依然是正常引用。
WeakMap 中,每个键对自己所引用对象的引用都是弱引用,在没有其他引用和该键引用同一对象,这个对象将会被垃圾回收(相应的key则变成无效的),所以,WeakMap 的 key 是不可枚举的。
属性:
方法:
5. 总结
6. 扩展:Object与Set、Map
Object 与 Set
Object 与 Map
JS 中的对象(Object),本质上是键值对的集合(hash 结构)
但当以一个DOM节点作为对象 data 的键,对象会被自动转化为字符串[Object HTMLCollection],所以说,Object 结构提供了 字符串-值 对应,Map则提供了 值-值 的对应
本文始发于我的博客:Set、WeakSet、Map及WeakMap
Set
1.成员不能重复
2.只有健值,没有健名,有点类似数组。
3. 可以遍历,方法有add, delete,has
weakSet
Map
weakMap
1.直接受对象作为健名(null除外),不接受其他类型的值作为健名