前言
大家好,我是 「艾伦」 ,是一名刚进入职场不久的前端er。为了给正在学习前端的女朋友排除万难,笔者决定开始一个全新专栏的更新,该专栏主要围绕经典的费曼学习法,用最容易理解的话教会前端小白前端学习中的技术点。因此,该专栏同样适用于正在学习前端基础知识的你。
这里会持续更新(要相信爱情的力量😝,欢迎监督催更),如果对你有帮助的话,欢迎关注!!!
当然,如果你觉得文章哪些点还不是很清晰,也欢迎在评论区讨论,期待和你一起成长~
正文
基础知识
-
Map 和 Set是什么? Map 和 Set 是ES6中提出的两种新的数据结构,可以通过类比对象 和 数组来学习
(温馨提示:注意区分 Map数据结构 和 JavaScript的遍历方法 map )
-
Map 和 Set 的特点(根据obj 和 array 对比学习)
-
Map 和 Set 怎么用?
-
WeakMap 和 WeakSet 的特点 (根据Map 和 Set 对比学习)
常见面试题
- 你在自学和工作中一般在什么场景下使用map?
- WeakMap的弱引用能解释一下吗?弱引用的是键还是值,如果弱引用对象被回收,WeakMap里的引用也会消失
WeakMap
是什么东西?
和map一样,用于生成键值对的集
和map的区别?
在使用上的区别:
- weakmap只接受对象作为键名(不包括null)
- weakmap的键名所指向的对象,不计入垃圾回收机制(这点和weakset相同,就是垃圾回收机制不会受这个引用的影响)
注意:进行弱引用的是键名,键值还是正常引用的
在API上的区别:
- 没有遍历操作(和weakset一样)所以没有keys、values、entries遍历方法 只有get、set、has、delete方法可用
为什么要设计出这个东西?
*问题:*当我们想要在对象上存放一些数据,这会导致我们对这个对象进行了引用。例子如下:
//仅对e1,e2 两对象进行了文字说明,造成了引用
const arr = [
[e1, 'foo 元素'],
[e2, 'bar 元素'],
];
然而当我们在别的逻辑不需要这个对象了,需要将他删除的时候,我们还要手动删除掉这个引用,否则垃圾回收机制不会释放这个对象占用的内存,造成内存泄漏。
weakmap就是为解决这个问题而生的。它的键名的引用是弱引用,垃圾回收机制不会考虑这个引用。
使用场景
*最大的用途:解决垃圾回收的问题 当你想要往对象上添加数据,又不想干扰垃圾回收机制,就可以使用weakmap 经典使用场景:
- 在网页的DOM元素上添加数据,就可以使用weakmap。当DOM被清除,weakmap保存的这个键名也会消失
- 部署私有属性:
const _counter = new weakMap()
const _action = new WeakMap()
class Countdown{
constructor(counter,action){
_counter.set(this,counter)
_action.set(this,action)
}
}
在上述代码中,在构造器中初始化属性,对实例this是弱引用。好处:如果删除实例,它们也会随之消失,不会造成内存泄漏
Map
特点
- 任何具有Iterator接口、且每个成员都是一个双元素的数组的数据结构都可以当作Map构造函数的参数。第一个元素作为key。第二个元素做value
- 在判别是否为相同属性的规则和Set一致:
- 对引用数据类型,始终认为时两个不同的键或值。
- 对普通数据类型,全等则视为相同
实例的属性和操作方法
- size属性:返回Map结构中成员总数
- set(key,value):设置键名key对应的值为value。然后返回整个map结构。如果key已经有值,则键值会被更新。可以采用链式写法
- get(key):读取key对应的键值并返回。如果找不到就返回undefined
- has(key):判断键是否在当前Map对象中
- delete(key):删除某个键。成功则返回true,反之,返回false
- clear():清除所有成员,没有返回值
遍历方法 —— 和Set一致
Map和其他数据结构的转换
- Map转为对象:直接循环拷贝一次即可,如果有非字符串键名,会自动转为字符串
- 对象转为Map:Object.entries(obj)(就是以[key , value]形式遍历所有项)
- Map转JSON:
- Map键名都是字符串,转为对象JSON
let obj = {"a":1, "b":2};
let map = new Map(Object.entries(obj));
WeakSet
- 和Set一样,也是不重复的值的集合
和Set的区别:
-
WeakSet的成员只能是对象,不能是其他类型的值。
-
WeakSet没有size属性,并且不能遍历它的成员。是因为成员都是弱引用,随时可能消失,遍历机制无法保证成员的存在,很可能刚刚遍历结束,成员就取不到了。WeakSet 的一个用处,是储存 DOM 节点,而不用担心这些节点从文档移除时,会引发内存泄漏。
-
其次,WeakSet中的对象都是弱引用,也就是说垃圾回收机制回收时不会考虑该对象是否还存在WeakSet之中。 原因: 因为垃圾回收机制依赖引用计数,如果一个值的引用次数不为0,立即回收机制就不会释放这块内存。结束使用该值之后,有时会忘记取消引用,导致内存无法释放,进而可能会引发内存泄漏。WeakSet没有这个问题。 使用场景: 因此,WeakSet适合存放一组对象,以及存放跟对象绑定的信息。只要对象在外部消失,它在WeakSet里面的引用就会自动消失。 注意
-
1、WeakSet的成员不适合引用,因为它随时可能消失.
-
由于 WeakSet 内部有多少个成员,取决于垃圾回收机制有没有运行,运行前后很可能成员个数是不一样的,而垃圾回收机制何时运行是不可预测的,因此 ES6 规定 WeakSet 不可遍历。
语法
- WeakSet可以接受任何具有Iterable接口的对象作为参数.如果接收的参数的成员是引用数据类型 , 那么它们会自动成为WeakSet实例对象的成员
- WeakSet的方法
- add(value):向实例中添加一个新成员
- delete(value):清除实例的指定成员
- has(value):返回一个布尔值,表示该值是否在实例之中
Set
- 是什么? ES6提供的一种新的数据结构,类似于数组,成员的值是唯一的,没有重复的值。
- 怎么用?
- Set是一个构造函数,用来生成Set数据结构
- 可以通过add()方法向Set结构加入成员,但不会添加重复的值
- Set函数可以接受一个数组(或具有iterable接口(即可以用来遍历的数据类型)的其他数据结构)作为参数,用来初始化 注意:
- 向Set加入值时,不会发生类型转换。所以
add(5)和add('5')是不一样的 - Set内部判断两个值是否相同,有自己的算法规则,类似于(===)类型和数据都相等,但还是有特殊情况的:
- 在Set内部认为NaN等于自身。即:
add(NaN)后,再一次add(NaN)被认为是重复的,set最终只会有一个NaN - 在Set中,两个对象总是不相等的。即
add({})后,再add({}),set.size为2
问题:为啥{} === {} 是false 引用数据类型比较的是引用,而不是值。两个不同的对象,引用地址显然不同,故为false
Set实例的方法和属性
- 属性
- Set.prototype.constructor 构造函数 = Set
- Set.prototype.size 返回Set实例的成员总数
- 方法
- 操作方法
- add(value) 添加默认值,返回Set结构本身
- delete(value) 删除某个值,返回布尔值,表示是否删除成功
- has(value)返回boolean值,表示该值是否是Set的成员
- clear():清除所有成员,没有返回值
- 遍历方法 注:Set的遍历顺序就是插入顺序。
- keys()
- values()
- entries():返回的遍历器,同时包含键名和键值,输出为一个数组,两个成员完全相同 注:前三种方法返回的都是遍历器对象,由于Set没有键名,只有键值,所以keys和values的行为完全一致》
- forEach():和数组的一样。第一个参数:回调函数。回调的参数为键值、键名、集合本身。第二个参数:绑定处理函数内部的this对象
- 注意:
- 因为Set的实例默认遍历,这意味着可以忽略values方法,直接用for...of循环遍历Set
- 使用set进行数组去重:1、Array.from 可以将Set结构转为数组。所以Array.from(new Set(array))是一种数组去重的方法。 2、利用扩展运算符和Set结构结合: [...new Set(arr)],就能达到去重的效果
- Set的重要应用
- 很容易实现并集、交集、差集
let a =newSet([1,2,3]); let b =newSet([4,3,2]); // **并集** let union=**newSet([...a,...b]);** // Set {1, 2, 3, 4} // **交集** let intersect =**newSet([...a].filter(x => b.has(x)));** // set {2, 3} // (a 相对于 b 的)**差集** let difference =**newSet([...a].filter(x =>!b.has(x)));** // Set {1}
- 如果想在遍历操作中,同步修改原来的Set结构,没有直接的方法,但有两种间接的方法:
// 方法一:通过map返回一个新的Set,最后赋值给原来的Set
let set=newSet([1,2,3]);
set=newSet([...set].map(val => val *2));
// set的值是2, 4, 6
// 方法二:
let set=newSet([1,2,3]);
set=newSet(**Array.from(set, val => val *2)**);
// set的值是2, 4, 6
另外: Array.from
- 参数
- 想要转换为数组的伪数组对象或可迭代对象(set\map\string\array都行)
- 回调函数。新数组中的每个元素都会执行该回调
- 上面回调函数执行时的this对象
- 返回值 一个新的数组实例
总结
介绍下Set、Map、WeakSet、WeakMap的区别?
- Set和WeakSet 以及 map和weakMap:
- Set的成员可以是任何数据结构,而weakset的成员只能是对象
- 在Set中对对象的引用都是正常引用,而weakset是弱引用,这种引用不会影响垃圾回收机制
- weakset不能遍历它的成员。weakset没有size属性和keys、values、entries这三个遍历方法
- set 和 map:
- set实例是一个不重复的值的集合,键名和值一致
- map实例是一个键值对得集合,任何得数据结构都能作为键名的对象
结语
备战秋招,这是复盘阶段系列文章第一篇。欢迎点赞持续关注,一起冲!!!