首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ES6的Set与Map

ES6的Set与Map

作者头像
Chor
发布2020-03-09 14:33:02
5360
发布2020-03-09 14:33:02
举报
文章被收录于专栏:前端之旅前端之旅

Set 和 Map 出现之前

在 ES5 中经常用对象来模拟实现 Set 集合与 Map 集合这两种数据结构,但这种做法带来了一些问题:比如利用 if(obj.size) 检查集合中是否存在某个元素的时候,预期行为是只要存在 size 就能通过 if 判断,但如果 size = 0,那么也无法继续执行,即使此时元素是存在的。另外,对象的键名只能是字符串,非字符串类型的键名也会通过 toString() 方法被转换成字符串,这意味着 obj[5]obj['5'] 没有区别,尽管我们本意是想创建两个不同的键;甚至,当键名是对象的时候,不管我们操作的是哪个键名(obj[key1] 或者 obj[key2]),实际操作的都是 obj['[object Object]'],这是因为对象会被转换成字符串 '[object Object]',这些都是与我们的预期不符合的。因此,ES6 推出了正式的 Set 和 Map 集合。

Set

调用 new Set() 可以创建一个 Set 集合,之后通过 add() 添加元素,size 访问元素数量。

let set = new Set()
set.add('one')
set.add('two')
set.size    // 2

与 ES5 中对象模拟实现不同的是,Set 集合会对添加进来的元素调用 Object.is() 检查是否一致,由于 5'5' 是不同的,所以 Set 可以同时存在这两个元素,不会发生类型转换(唯一的例外是 +0-0,尽管 Object.is(+0,-0) 返回 false,但是 Set 集合认为这两个是一致的);同理,也可以添加多个独立对象,它们是不会被转换成字符串的。

set.add(5)
set.add('5')
let key1 = {}
let key2 = {}
set.add(key1)
set.add(key2)
set.size  // 4

还可以用 has() 检测是否存在某个元素,用 delete() 移除指定元素,用 clear() 清空整个 Set 集合。

另外,创建 Set 集合的时候支持传参,我们可以使用像数组这样的可迭代对象来初始化 Set 集合(这也是将数组转换成 Set 集合的方法):

let set = new Set([1,2,2,3,4])
set.size  // 4

注意:Set 集合为了保证集合元素唯一,会对数组进行元素过滤,这一点稍后可以用来进行数组去重。

那么如何访问集合元素呢?由于 Set 集合没有键名,所以不可能像数组那样通过数值型索引值去访问某个元素,要访问 Set 集合的元素,我们需要先将集合转换成数组。这个使用展开运算符 ... 来实现:

let set = new Set()
set.add(1)
set.add(2)
let array = [...set]
array   // [1,2]

数组转换成集合+集合转换成数组,就可以实现数组去重:

let array = [1,2,2,3,4,5,6,6]
let anotherArray = [...new Set(array)]   // [1,2,3,4,5,6]

此外,可以用 forEach() 来迭代 Set 集合中的元素,该方法的回调函数接受三个参数:valuekey 以及集合本身。虽然 Set 没有 key 键名,但为了与数组和 MapforEach() 保持一致,依然提供了 key 参数,它的值与 value 是一样的。

Weak Set

上面的 Set 是一个强引用的集合,这指的是,如果集合中存储着对象的引用(set.add(obj)),那么即使我们已经在集合外面清除了对该对象的引用(obj = null),集合中的引用也不受影响。为了避免造成内存泄漏,我们需要一种弱引用的集合,也就是 Weak Set。

Weak Set 只存储对象的弱引用,所以如果把集合外面对象的最后一个强引用移除,则 Weak Set 中的引用也不复存在,这样就避免了内存泄露的情况。此外,它还有一些特点:

  • 不可以存储原始值,否则报错
  • 不可迭代,所以不能使用 forEach()clear()
  • 不支持 size 属性
  • 不暴露诸如 keys()values() 等迭代器

Map

相比 Set,Map 存储的是多对键值对,并且键名和键值支持所有的数据类型。

调用 new Map() 可以创建一个 Map 集合,之后通过 map.set(key,value) 添加键值对,map.get(key) 访问指定键名的键值。

let map = new Map()
let obj = {}
map.set('name','Jack')
map.set(obj,'I am object')     // 不同于对象,在 Map 中键名可以是对象
map.get('name')  // 'Jack'
map.get(obj)     // 'I am object'
map.get('unexisted key')  // 访问不存在的键,返回 undefined

Map 同样也有 has(key)delete(key)clear()size (返回键值对对数)等方法和属性。

另外,可以使用数组来初始化 Map 集合,批量添加元素。由于 Map 中的元素是键值对,所以传入的数组的元素也是数组:

let  map = new Map([['name','Jack'],['age',12]])
map.get('name')   // 'Jack'
map.get('age')    // 12
map.size          // 2

Map 的 forEach() 方法的回调函数也接受三个参数:valuekey 以及集合本身,这和数组更为接近,只不过数组对应的第二个参数是数值型索引值。

Weak Map

类似的,Map 也有弱引用集合 Weak Map。Weak Map 的键名必须是对象,且保存着对象的弱引用(如果集合外面引用被清除,则集合中的引用也不复存在,且键值对会跟着被移除);键值则不一定是对象,且当键值是对象时,它保存的依然是强引用。也就是说,Weak Map 的弱引用是针对键名来说的。

Weak Map 可以用来跟踪对象的引用,进而确保将来某一刻需要清除的对象的内存一定能够得到释放,不发生潜在的内存泄露。

举例来说,现在有一个 DOM 元素,它接受用户的输入并将输入的信息存储在一个对象中,如果没有使用 Weak Map ,那么维系 DOM 对象输入信息对象 的映射关系时就有可能产生一个新的关于 DOM 对象的强引用,而在之后清除 DOM 对象原先的强引用时,该强引用可能不会被清除,这导致对象内存实际没有得到释放。但是,如果使用了 Weak Map,将 DOM 对象作为键名,输入信息对象作为键值,那么由于 Weak Map 存储的是对象的弱引用,此时就一定能保证 DOM 对象被移除后(且集合外围对象的最后一个强引用被清除),其内存能够得到释放,不会发生内存泄露的问题。

此外,Weak Map 也可以用来存储对象实例的私有变量:

let Person = (function(name,age){
    let privateData = new WeakMap()
    function Person(){
        privateData.set(this,{name:name,age:age})
    }
    Person.prototype.getName = function(){
        return privateData.get(this).name
    }
    Person.prototype.getAge = function(){
        return privateData.get(this).age
    }
}())

在上面的这段代码中,存在着一个 Weak Map(privateData)用来维系多个实例与自身私有变量的映射关系。每次创建新实例的时候,都会往 privateData 这个集合中添加新的”映射条目“(privateData.set(this,{name:name,age:age}),其中,this 指的是实例),键名是实例,键值是存储私有变量的对象。这么一来,当未来某一天删除实例的时候,由于集合外围的实例对象的强引用被移除,Weak Map 存储的又是实例对象的弱引用,所以保证了实弱引用也会被垃圾回收,不存在内存泄漏的问题。简而言之,只要实例被销毁,相关信息也会跟着销毁,这样就保证了信息的私有性。

此外,Weak Map 还有一些特点:

  • 不支持 size 属性
  • 不可迭代,因此不支持 forEach()clear()
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-03-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Set 和 Map 出现之前
  • Set
  • Weak Set
  • Map
  • Weak Map
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档