【ES6系列】详解Set和Map两种数据结构

前言

相信大家在刷算法题时,应该都碰到过Map 数据结构,它可以解决一些与键值对相关的问题,例如快速查找、存储关联信息等。可是很多人对这两个数据结构并没有那么熟悉,导致许多应用场景或者面试的过程中无法理解它们的真正含义,那么本文将带领大家彻底搞懂Set和Map。

Set

定义方法new Set(),通过Set构造函数生成Set数据结构,且接受一个数组作为参数

1.是一种 key和value相等的特殊对象

vbscript 复制代码
let set = new Set([1,2,3,4])
console.log(set); // Set(4) { 1, 2, 3, 4 }

很明显,打印出的set对象{1, 2, 3, 4}很特殊,没有键,只有值,可以推测Set实例对象是一个key和value相等的特殊对象。我们可以把它理解成用于存储唯一值的集合。 我们再去浏览器上看看Set对象的真面目:

怎么样是不是非常像数组,所以Set也跟类数组很类似,所以很多小伙伴会觉得访问Set中的元素和数组类似,通过下标访问即可,可事实并非如此!

当你打印Set[0]时,你会发现结果是undefined。说明Set中的元素是不能通过下标访问的,一定要记住!如何访问请继续往下读。

2.set 对象中的值是唯一的

vbscript 复制代码
let set = new Set([1,2,2,3,4])
console.log(set); // Set(4) { 1, 2, 3, 4 }

只要是定义在Set对象中的值,一定不存在重复的现象。

所以通过这个特性,Set也经常用于数组的去重操作:

javascript 复制代码
var arr = [1,2,1,1,'1']
var unique = (arr) => Array.from(new Set(arr))
console.log(unique(arr)); //[1,2,'1']

Array.from()方法可以将 Set 结构转为数组。箭头函数返回 Array.from(new Set(arr)) 或者 [...new Set(arr)]都没问题。扩展运算符(...)内部使用for...of循环,所以也可以用于 Set 结构。

3.Set 实例的属性和方法

属性: Set.size:返回Set实例的成员总数,与数组身上的length类似

常用方法: add、clear、delete、has

csharp 复制代码
let set = new Set([1,2,2,3,4])
set.add(1) //添加某个值,返回 Set 结构本身。
set.clear() //  清除所有元素,没有返回值
set.delete(1) //true  删除一个元素,返回一个布尔值,表示删除是否成功。
set.has(1) //true  判断Set是否存在该值,返回布尔值

4. Set遍历、具有迭代器(iterator)属性

Set实例具有迭代器 属性,这也意味着Set实例可被for..of 遍历,但是我们一般给Set实例的keys方法、values方法、entries方法返回的值遍历:

csharp 复制代码
let set = new Set([1,2,3,4])
for (let i of set.keys()){ //返回所有的键名
    console.log(i); // 1 2 3 4
}
for (let i of set.values()){ //返回所有的键值
    console.log(i); // 1 2 3 4
}

 for (let i of set.entries()){ //键的名和值均返回,输出为一个数组
    console.log(i); // [1,1] [2,2] [3,3] [4,4]
}

当然你直接给Set实例遍历也是可以的。

Set实例也可以使用forEach方法遍历:

javascript 复制代码
let set = new Set([1,2,3,4])
set.forEach(el => {
    console.log(el); // 1 2 3 4
})

Map

定义方法: 定义方法new Map(),通过Map构造函数生成Map数据结构,且接受一个二维数组数组作为参数,或者说接受一个数组作为参数。该数组的成员是一个个表示键值对的数组。

ini 复制代码
let map = new Map([
  ['name', '张三']
]);

1. 可以用任意数据类型做key的特殊对象

传统的对象中的key只能为字符串类型,新增的Map实例中的key可以为任意类型。

但是我们要注意,如果将引用类型做为key的话,有几个小坑

arduino 复制代码
let map = new Map([
  ['name', '张三']
]);
map.set({a: 1}, 2) // 添加元素
map.get({a :1}) // 访问元素

那么这里的get方法能访问到值吗?答案是不能,原因很简单,这里set中的{a: 1}get中的{a: 1}是不一样的!两者虽然值相同,但是对于引用类型的值来说,引用地址也要一样。

解决方法:用一个变量将对象存下来。

csharp 复制代码
let map = new Map([
  ['name', '张三']
]);
let obj = {a: 1}
map.set(obj, 2) 
map.get(obj) // 2

2. Map实例的属性和方法

属性: size属性返回 Map 结构的成员总数。

常用方法:set、get、delete、clear、has

csharp 复制代码
let map = new Map()
set.set(1,2) 
set.get(1) //2
set.delete(1) //true  
set.has(1) //true  
set.clear() 
  1. set方法设置键名key对应的键值为value,然后返回整个 Map 结构。如果key已经有值,则键值会被更新,否则就新生成该键。
  2. get方法读取key对应的键值,如果找不到key,返回undefined
  3. has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。
  4. delete()方法删除某个键,返回true。如果删除失败,返回false
  5. clear()方法清除所有成员,没有返回值。

3. Map遍历、具有迭代器(iterator)属性

Map实例也具有迭代器属性,foreach和for...of遍历均可:

arduino 复制代码
//foreach
map.forEach((value,key,map) => {
    console.log(value,key,map);
})

2.for...of
for(let i of map){
    console.log(i);
}

聊聊WeakSet、WeakMap

因为WeakSet、WeakMap的特殊之处类似,所以我就用WeakSet作为代表。

WeakSet 结构与 Set 类似,也是不重复的值的集合。我们只需知道它与 Set 有两个区别。

1.WeakSet 的成员

WeakSet 的成员只能是对象和 Symbol 值,而不能是其他类型的值。

csharp 复制代码
const ws = new WeakSet()
ws.add(1) //报错
ws.add(Symbol()) // 不报错

2.WeakSet 中的对象都是弱引用

简单来说,一个对象被WeakSet所引用,在垃圾回收机制的眼中,该对象是没有被引用的。也就是说当其他对象都不再引用该对象时,只要垃圾回收机制一生效,该对象所占据的内存空间就会被销毁。

javascript 复制代码
let obj = { name: '德玛西亚'}

let ws = new WeakSet()
ws.add(obj) //不考虑,obj直接销毁
obj = null //相当于手动销毁obj

console.log(ws) //空对象

相信很多小伙伴都尝试了一下上面的代码吧,但是打印结果令人大跌眼镜,ws依旧保存着obj。那么这个现象是非常正常的,因为垃圾回收机制不是可控的,可能我们打印的时候垃圾回收机制还未生效罢了,所以ws理论上就是一个空对象。

最后

希望本文对大家能有帮助!

文章参考:

阮一峰的ES6入门教程

相关推荐
也无晴也无风雨28 分钟前
深入剖析输入URL按下回车,浏览器做了什么
前端·后端·计算机网络
Martin -Tang1 小时前
Vue 3 中,ref 和 reactive的区别
前端·javascript·vue.js
SRY122404192 小时前
javaSE面试题
java·开发语言·面试
FakeOccupational3 小时前
nodejs 020: React语法规则 props和state
前端·javascript·react.js
放逐者-保持本心,方可放逐3 小时前
react 组件应用
开发语言·前端·javascript·react.js·前端框架
曹天骄4 小时前
next中服务端组件共享接口数据
前端·javascript·react.js
阮少年、4 小时前
java后台生成模拟聊天截图并返回给前端
java·开发语言·前端
不二人生5 小时前
SQL面试题——连续出现次数
hive·sql·面试
郝晨妤5 小时前
鸿蒙ArkTS和TS有什么区别?
前端·javascript·typescript·鸿蒙
AvatarGiser6 小时前
《ElementPlus 与 ElementUI 差异集合》Icon 图标 More 差异说明
前端·vue.js·elementui