You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
letset1=newSet([1,2,3])letset2=newSet([4,3,2])letintersect=newSet([...set1].filter(value=>set2.has(value)))letunion=newSet([...set1, ...set2])letdifference=newSet([...set1].filter(value=>!set2.has(value)))console.log(intersect)// Set {2, 3}console.log(union)// Set {1, 2, 3, 4}console.log(difference)// Set {1}
为啥有问题?好好看报错!cannot read property Symbol(Symbol.iterator) 也就是说,如果你想创建一个可迭代对象,你需要让这个对象(类)拥有一个私有标识:Symbol.iterator 。确切地来说,Set 的构造器要求对象具有的这一私有的标识,本质上要求应该是一个“具有 next 方法、且每次 next 方法会返回一个具有 done 和 value 两个属性的对象”的方法,done 的值为布尔值、为 false 则可以继续执行 next 取下一个值。多说无益,show u my code :
varfoo={0 : 'zero',1 : 'one',2 : 'two',3 : 'three',length : 4};foo[Symbol.iterator]=function(){leti=0;letl=this.length;letthat=this;console.log('someone is using the iterator')return{next(){if(i<l){console.log('now:'+that[i]+',progress:'+i+'/'+l)return{done: false,value: that[i++]};}return{done: true};}};}newSet(foo);
letset1=newSet([1,2,3])letset2=newSet([4,3,2])letintersect=newSet([...set1].filter(value=>set2.has(value)))letunion=newSet([...set1, ...set2])letdifference=newSet([...set1].filter(value=>!set2.has(value)))console.log(intersect)// Set {2, 3}console.log(union)// Set {1, 2, 3, 4}console.log(difference)// Set {1}
letset1=newSet([1,2,3])letset2=newSet([4,3,2])letintersect=newSet([...set1].filter(value=>set2.has(value)))letunion=newSet([...set1, ...set2])letdifference=newSet([...set1].filter(value=>!set2.has(value)))console.log(intersect)// Set {2, 3}console.log(union)// Set {1, 2, 3, 4}console.log(difference)// Set {1}
Activity
zero578 commentedon Jan 25, 2019
Set
1.成员不能重复
2.只有健值,没有健名,有点类似数组。
3. 可以遍历,方法有add, delete,has
weakSet
Map
weakMap
1.直接受对象作为健名(null除外),不接受其他类型的值作为健名
[-]Set、Map、WeakSet 和 WeakMap[/-][+]第四题:Set、Map、WeakSet 和 WeakMap[/+]sisterAn commentedon Feb 16, 2019
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
peakDragonCheung commentedon Feb 18, 2019
4 Object 转化为 Map , 其中一行代码 map.set(key, obj[k]) 这里是不是写错了,不是 obj[k],而是obj[key]。
peakDragonCheung commentedon Feb 18, 2019
sisterAn commentedon Feb 18, 2019
ok,已改正,谢谢 @peakDragonCheung
kscript commentedon Feb 19, 2019
WeakMap 里有一段写成了 WeakSet。
BeADre commentedon Feb 19, 2019
Set 实例方法下面遍历方法中使用map、filter那个地方 打印写错了 应该是[2,3,4]和[4]吧
wenbintian commentedon Feb 19, 2019
在 “与其他数据结构的相互转换 的 4.Object 转 Map” 参数名称写错了, 应该是 “obj” 而不是 "map"
ghost commentedon Feb 22, 2019
我觉得看这篇技术文章也可以
zhoufanglu commentedon Feb 28, 2019
new Set([1,2,3]).length 值应该是undefind 而不是0
noctiomg commentedon Apr 21, 2019
为了学习 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 的福利正在逐渐普及,和我一样是万年切图仔的同学们也要适当充实下自己在基础方面的知识,不要只知其然不知其所以然啦~
[-]第四题:Set、Map、WeakSet 和 WeakMap[/-][+]第 4 题:介绍下 Set、Map、WeakSet 和 WeakMap 的区别?[/+]qiufeihong2018 commentedon May 5, 2019
@sisterAn 差集有问题啊
12 remaining items
yft commentedon Sep 5, 2019
应该不能说 Set 可以使用 map filter 方法吧,只是 Set 和数组互转很方便,结合数据的 map filter 方法,可以实现很方便的交集、并集、差集。
XiaoDHuang commentedon Dec 31, 2019
关于weakMap与weakSet弱引用该如何理解
弱引用是向weakSet/weakMap中添加一个目标对象的引用,但添加是目标对象的引用计数不增加。比较来说:
到这里,由于对象的引用计数为0了,所以weakSet中的那个被add()进去的x、y就自动被回收了。——weakSet/weakMap具备这种机制。
所以weakSet/weakMap没有size这个属性,它不安全。——你刚读了它的值,它自己自动回收了一下,就又变掉了。
如果感兴趣大家可以通过链接去订阅(只想表示很硬核)http://gk.link/a/10fj0
guestccc commentedon Feb 27, 2020
@sisterAn 差集错了,应该是
wulichenyang commentedon May 11, 2020
老哥你很喜欢健身吗?
lanshanmao commentedon May 28, 2020
Set不是没有键名,是键名和值相同,const set = new Set() set.add(444) set.keys()可获得键名的Iterator对象,set.forEach可遍历
soraly commentedon Jun 11, 2020
Set: 1. 成员唯一、无序且不重复 2. [value, value],键值与键名是一致的(或者说只有键值,没有键名)
3. 可以遍历,方法有:add、delete、has
WeakSet: 只能插入对象,否则会报错。弱引用,可以被垃圾回收机制回收。所以适合用来保存DOM节点,不容易造成内存泄漏。不可遍历。方法同Set
Map: 本质上是键值对的集合,类似集合,key不局限于字符串,方法有get、set、has、delete
RoeyXie commentedon Jul 28, 2020
🧡 Map类似于对象,它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
🧡 Set类似于数组,与数组的区别是它的成员值都是唯一的,是不重复的。
🧡 WeakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有两个区别。
首先,WeakSet 的成员只能是对象,而不能是其他类型的值。其次,WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。
这是因为垃圾回收机制依赖引用计数,如果一个值的引用次数不为0,垃圾回收机制就不会释放这块内存。结束使用该值之后,有时会忘记取消引用,导致内存无法释放,进而可能会引发内存泄漏。WeakSet 里面的引用,都不计入垃圾回收机制,所以就不存在这个问题。因此,WeakSet 适合临时存放一组对象,以及存放跟对象绑定的信息。只要这些对象在外部消失,它在 WeakSet 里面的引用就会自动消失。
由于上面这个特点,WeakSet 的成员是不适合引用的,因为它会随时消失。另外,由于 WeakSet 内部有多少个成员,取决于垃圾回收机制有没有运行,运行前后很可能成员个数是不一样的,而垃圾回收机制何时运行是不可预测的,因此 ES6 规定 WeakSet 不可遍历。这些特点同样适用于WeakMap 结构。
🧡 WeakMap结构与Map结构类似,也是用于生成键值对的集合。WeakMap与Map的区别有两点:首先,WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名。其次,WeakMap的键名所指向的对象,不计入垃圾回收机制。
moruifei commentedon Jul 30, 2020
Set对象并非只有键值没有键名 只是键值键名一样而已。
Cosen95 commentedon Dec 4, 2020
整理的很不错,学习了~
zhipairen commentedon Jan 4, 2021
WeakSet与Set不同点:
1、类Set的结构,但WeakSet的健值只能为对象,不允许存储基本类型值
2、WeakSet为弱映射,只有在可访问的情况下,才能存储在set中,若set中的值被垃圾回收,则自动清除
3、WeakSet 不可迭代,不能调用 size、keys() 等方法;注: 垃圾回收下,不能确定WeakSet下有效的键值,故不能获取所有值
WeakMap与Map不同点:
1、类Map的集合,但 WeakMap的键名必须为对象
2、WeakMap为弱集合,在垃圾回收时,可被标记回收;
3、WeakMap不支持迭代及不能调用keys()、values()、entires()方法
sy19971224 commentedon Mar 3, 2021
set确定能使用map、filter方法吗?我自己试是报错的哇,数组的方式应该不能给set用吧
alanhe421 commentedon Mar 10, 2021
用call就行了,因为set是可迭代的。
90neoCulture commentedon May 11, 2021
map转obj那块,需要加上判断key的类型,因为map的key可以是任意类型,而obj不可以