js引用数据类型:对象、数组、函数、日期、正则、set、map
在讲set-map之前我需要带大家认识下迭代器iterator
这个属性
迭代器iterator
能够被for…of遍历的东西才具有迭代器属性
- 这个属性字节面试被问过
for...of
for...of
用例如下
1 | javascript复制代码javascript |
js中遍历方法太多了,但for...of
这个遍历方法是专门供具有迭代器属性的数据结构来使用的。从上面用例我们就可以看出,数组、字符串都具有迭代器属性,但是普通对象是没有的,这里我对对象强调普通二字是因为Set和Map。
Set
- 是一种key和value相等的特殊对象
- set对象中的值是唯一的
- 具有迭代器(
iterator
)属性
set是一个类数组
上一次聊类数组还是介绍arguments这个东西,大家感兴趣可以去看看关于arguments这个函数属性的文章深入认识js四大常用数据类型判断,一次性带你搞明白(内含面试热点)! - 掘金 (juejin.cn)
arguments是函数中形参的统称
什么是类数组呢?
类数组本质上是一种对象,它与数组类似,具有数组的下标和长度属性,其他数组的方法它都没有,如
pop、push
等
set如何创建呢?又如何查看呢?
1 | vbscript复制代码vbscript |
set是没有符号表达,它的表示方法就是上面这样,接受的参数必须是个数组,并且值唯一,如果我们重复放元素进去,最终得到的元素将会是去重后的
如果我们重复放值进去
1 | vbscript复制代码vbscript |
第一次见识到这个东西的时候我觉得很牛,完全可以用set方法对一个数组去重
去重
1 | javascript复制代码javascript |
想要用set对一个数组去重,最后输出还是一个数组,就必须进行一个转换,Array.from
的作用就是专门用来将类数组转换成数组,当然你也可以直接用es6新增的解构进行输出,解构同样适用于类数组
下面开始介绍set的方法
has方法
has方法用于查看set中值是否存在
1 | vbscript复制代码vbscript |
set并不能直接通过下标方法进行查看单个值,只能判断值有没有
add方法
add方法其实就像数组中的push,从尾部增加新值
1 | vbscript复制代码vbscript |
size属性
size就是数组的length,查看大小
1 | arduino复制代码arduino |
delete方法
删除指定的元素
1 | sql复制代码sql |
clear方法
清空set中所有的值
1 | vbscript复制代码vbscript |
forEach方法
对set进行遍历
1 | dart复制代码dart |
从这里可以发现:set中的key和value是相同的!
既然set可以被自己的方法遍历,那能否被for...of
遍历,看看他是否具有迭代器属性
1 | csharp复制代码csharp |
是有的,不过我们用set.keys()
迭代会更多一点
这些方法都是用实例对象来调用的,因此我们可以推断出这些方法都是挂在Set原型上的,不妨去浏览器看看都有哪些
常用的方法其实上面已经都介绍了,里面的Symbol(Symbol.iterator)
就是迭代器属性
Map
- 可以用任意数据类型作key的一种对象
- 也具有迭代器属性
普通对象的key是个字符串类型,我们不妨试试把一个数组挂到一个对象里面去当key
1 | css复制代码css |
这里需要注意,当你想添加某个key去作对象的属性的时候,我们要用中括号,而非点,如果这里用
obj.arr = 3
,那么arr则被当成一个key
根据这个输出结果可以看出,这个数组中的元素成为了字符串。
所以map就解决了这个问题,map的意义,就是可以用任意数据类型做key,因此,你可以理解为进阶版的对象,弥补了普通对象的不足之处,这个东西出现的频率高于set。
map和set同样,都没有符号去表达,如何创建呢,如下
1 | lua复制代码lua |
括号里面是也是个数组的形式,每个元素作为一个键值对
下面开始介绍map的方法
get方法
获取键对应的值
1 | arduino复制代码arduino |
set方法
这里的set是map中的方法,不是上面讲的set引用类型,不要搞混淆了噢
1 | arduino复制代码arduino |
这里解释下为什么倒数第二个不能打印,get查找方法是根据引用来查的,也就是地址,因此必须要用一个东西来装这个地址再来get。
这里突然想起一个小知识点,{} === {}
1 | less复制代码less |
对于引用类型来说,每个对象都是不一样的,这里指的是地址噢,哪怕内容相同,上期文章说过,三个等于号===
对于引用类型来讲,比较的是值,数据类型和地址。
forEach方法
其实map和set的这个方法都是遍历,但是map有点不同在于参数顺序反了
1 | dart复制代码dart |
map这里是先输出值,再输出键
map是否有迭代器呢
1 | arduino复制代码arduino |
也有,但是我们通常会用map.entries()
另外和set一样,也有has、delete、clear、size、keys等方法
我们去浏览器中看看map原型的方法
基本上都带大家认识了一遍,各位小伙伴也可以自己试试。
WeakSet
WeakSet和Set类似,你也完全可以理解为阉割之后的Set
- WeakSet只能存储对象和Symbol类型
- WeakSet没有迭代器属性,不可遍历
- WeakSet只有add、delete、has方法
- WeakSet是弱引用,不被垃圾回收机制所注意
下面就按照这个顺序讲一下:
WeakSet创建和Set一样,用实例对象
1 | javascript复制代码javascript |
现在我们来验证下存放的类型是不是只能是对象和Symbol
1 | csharp复制代码csharp |
没问题的,这里的原始类型我只验证了数字类型,原始7个中除了Symbol中,其余都是会报错的,引用类型都可以当作对象,你放函数,日期,数组都可以
我看到很多人的介绍文章都说只能是对象,不能是原始,咳咳,什么年代的文章,该提醒他们去更新下了
WeakSet是阉割版的Set,它没有迭代器属性,额……这个我咋解释,要不你们就接受他吧[doge]
因为它不被垃圾回收机制注意,随时被收走,不会被遍历,合理!
WeakSet是阉割版的Set,里面的方法只剩下这三个(add、delete、has)了,和上面的Set一样,我这里也不赘述了
弱引用和垃圾回收机制—重头戏来了!
弱引用:如果WeakSet中的对象在其他地方没有强引用,那么垃圾回收机制会自动清理掉该对象
垃圾回收机制真要讲这里是讲不完的,但是可以说的是,JavaScript中垃圾回收机制是自动进行的,不像C语言一样,需要free手动释放
讲到垃圾回收机制了,就要扯到内存,穿插一个小知识点(突然想到的)
1 | css复制代码css |
肯定有小伙伴以为这里会报错,const不能改变啊,但是这里其实就是因为一个内存问题,引用类型真正存在堆(heap)中,存在栈(stack)中的只是一个地址,所以a其实是个地址,a.push(1)
就是沿着地址从栈跑到堆中找到这个数组,添加一个新值,最后输出a这个数组
好,回到正题,我们以前用普通对象的时候都是一个强引用,比如
1 | css复制代码css |
这段代码对于浏览器来说,执行第一行代码的时候,垃圾回收机制(Garbage Collection),我们就形象地称他为清洁工(GC)吧,这个清洁工他会看下下面是否引用(强引用)了,下面需要打印这个对象就是一个强引用,如果没有强引用,执行完了let obj= {name: '小黑子'}
这行代码,清洁工就会把它扫走
obj = null
这是众多垃圾回收机制中的一种,称为引用计数(这也是早期的GC方法,因为无法用在循环中,现在不再使用)。让一个对象等于null,就是给了这个对象一个垃圾的标签,等待清洁工去清理
1 | ini复制代码ini |
而弱引用对于清洁工(GC)来说,GC是无视它的,一个对象只要是被WeakSet了,就会被弱引用,那么清洁工就会来清理它,这么说,那WeakSet的存在意义是什么?我们不妨来验证下是否果真如此
啊?浏览器的GC没有清理它!这是什么情况?
那我手动去清理它
GC还是没有去清理他,好吧,不卖关子了!其实这个bug曾经在StackOverflow里面广为流传,其原因是浏览器的GC是不受我们控制的,我们也无法得知GC何时执行
我们也可以在node中查看heapUsed
当然我们运行需要输入
node --expose-gc myTest.js
才能查看
1 | javascript复制代码javascript |
node中需要我们手动扫走他,浏览器扫没扫走你也无法控制
阮一峰老师讲弱引用的话术是下面这样的
话语比较官方,可能比较难以理解,总之,你要清楚的是浏览器清理机制你也无法控制,弱引用的对象如果后面没有强引用,GC会自动把他清走
应用场景
WeakSet其实就是可以解决一个内存泄漏问题,比如我们给一个按钮打上禁用,如果我们用了Set,这样是强引用,会浪费空间,WeakSet就可以回收掉这个浪费的空间,因为理论上来讲他就是空的,迟早会被清空掉
1 | xml复制代码xml |
WeakMap和WeakSet同理,是弱引用版本的Map,随时可能被浏览器GC清走
文章参考书籍:ECMAScript6入门—阮一峰
Set 和 Map 数据结构 - ECMAScript 6入门 (ruanyifeng.com)
如果觉得本文对你有帮助的话,可以给个免费的赞吗[doge] 还有可以给我的gitee链接codeSpace: 记录coding中的点点滴滴 (gitee.com)点一个免费的star吗[星星眼]
本文转载自: 掘金