深入理解ES6-7.Set集合和Map集合

41 阅读4分钟

Set集合

Set类型是一种有序列表,其中的值不能重复

方法和属性

  1. 调用 new Set() 创建Set集合,Set构造函数的参数是可迭代对象,初始化时会过滤掉重复的值。
  2. 调用其 add 方法添加元素,当使用 add 添加重复的值,后面的添加会被忽略。
  3. 使用其 size 属性获取元素数量。
  4. has 方法可用于检测Set集合中是否存在某值。
  5. 调用 delete 方法移除某个元素,clear 方法移除所有元素。
  6. 使用 forEach 遍历Set集合,只是callback前两个参数(index/item)是相同的。

转换数组

适合用于数组去重的操作。

// 数组转Set,直接传入Set构造函数
let set = new Set([4, 2, 3, 3]);
// Set转数组,使用展开运算符
let array = [...set]

Weak Set集合

将对象存储在Set实例与存储在变量中一样,只要在Set实例中的引用存在,垃圾回收机制就不能释放该对象的内存空间,普通的Set集合就是一种强引用。

let set = new Set(),
    key = {name:'phoeny'};
set.add(key);
key = null;

set存放的其实是对象的引用,当执行 key = null 的时候,是切断了key这个变量名和对象之间的联系,但是set中的值和对象之间的引用仍然存在。所以在垃圾回收的时候,这个对象仍是有引用指向的,就不会被回收。

在大部分的情况,强引用Set是我们希望得到的。但在有些情况我们会希望,如果其他引用都不存在了,就让Set集合中的引用也消失。

  1. WeakSet集合使用 WeakSet 构造函数创建,构造函数的参数是可迭代对象。
  2. WeakSet只支持3个方法:add/has/delete
  3. 如果WeakSet中的弱引用是对象的唯一引用,则对象会被回收并释放相应内存。
  4. 如果 WeakSet 构造函数的参数包含非对象值则会报错,因为它不接收任何原始值
let set = new WeakSet(),
    key = {name:'phoeny'};
set.add(key);
// 虽然看不出有什么不同,但稍后垃圾回收机制运行的时候,会将对象回收的
key = null;

如果你只需要跟踪对象引用,推荐使用 WeakSet 集合,而不是普通 Set 集合。

Map集合

Map 类型是一种存储许多键值对有序列表。

对象的属性名总会被强制转换为字符串,所以数字5和字符串'5'会当初一个属性,但是Map中是使用Object.is()判断键名的,所以它们会被作为两个独立的键名存在。

在对象中,无法使用对象作为键名,但Map可以。

创建Map

调用 new Map() 创建Map集合,传入的参数也是数组,数组中的每一项是一个两元素数组,第一个元素是键名,第二个元素是键值。

let map = new Map([ ['name','Nicholas'], ['age',25] ])

方法和属性

  1. 调用其 set 方法传入键名和键值, get 方法通过键名获取键值。
  2. 使用其 size 属性获取键值对数量。
  3. has 方法可用于检测Map集合中是否存在指定键名。
  4. 调用 delete 方法移除某个键值对,clear 方法移除所有键值对。
  5. 使用 forEach 遍历Map集合。

Weak Map集合

WeakSet 是弱引用的 Set集合,WeakMap 是弱引用的 Map集合。WeakMap 类型是一种存储许多键值对无序列表。

WeakMap的键名必须是一个对象,如果使用非对象会报错。WeakMap 的弱引用是针对键名的,键值如果是对象则还是保存的是对象的强引用。如果除了 WeakMap 中键名的弱引用之外,没有其他强引用,那么这个对象会被垃圾回收,同时移除 WeakMap 中的键值对。

WeakMap 只支持4个方法:get/set/has/delete

WeakMap 多用于存储DOM元素,也可以存储对象实例的私有数据。

私有数据

在es5中我们会使用闭包来模拟私有数据:

// 只能通过 getName 方法获取 _name 属性,不能直接访问
var Person = (function () {
    var privateDate = {},
        privateId = 0;
    function Person(name) {
       // 避免在外面重写 _id 属性
        Object.defineProperty(this,'_id',{
            value: privateId++,
            writable:false
        })
        privateDate[this._id] = {
            name: name
        }
    }
    Person.prototype.getName = function () {
        return privateDate[this._id].name;
    };
    return Person;
}());
let person = new Person('phoeny');
person.getName();    // phoeny
person.name;         // undefined
person._id;          // 0

利用es6中的WeakMap:

let Person = (function(){
    let privateDate = new WeakMap();
    function Person(name){
        privateDate.set(this,{name:name});
    }
    Person.prototype.getName = function(){
        return privateDate.get(this).name;
    }
    return Person;
}());
let person = new Person('phoeny');
person.getName()
person._name