Set 与 WeakSet

Set 对象允许存储任何类型的唯一值,无论是原始值或者是对象引用, Set 对象中的值不会重复。
WeakSet 对象允许存储对象弱引用的唯一值, WeakSet 对象中的值同样不会重复,且只能保存对象的弱引用。

Set

描述

Set 对象是值的集合,可以按照插入的顺序迭代它的元素, Set 中的元素只会出现一次,即 Set 中的元素是唯一的,常用来作数组去重。

属性与方法

属性和方法 功能
Set.prototype.constructor 返回构造函数。
Set.prototype.size 返回 Set 对象的值的个数。
Set.prototype.add(value) Set 对象尾部添加一个元素,返回该 Set 对象。
Set.prototype.clear() 移除 Set 对象内的所有元素。
Set.prototype.delete(value) 移除 Set 的中与这个值相等的元素。
Set.prototype.entries() 返回一个新的迭代器对象,该对象包含 Set 对象中的按插入顺序排列的所有元素的值的 [value, value] 数组,为了使这个方法和 Map 对象保持相似, 每个值的键和值相等。
Set.prototype.forEach(callbackFn[, thisArg]) 按照插入顺序,为 Set 对象中的每一个值调用一次 callback ,如果提供了 thisArg 参数,回调中的 this 会是这个参数。
Set.prototype.has(value) 返回一个布尔值,表示该值在 Set 中存在与否。
Set.prototype.keys() 返回一个新的迭代器对象,该对象包含 Set 对象中的按插入顺序排列的所有元素的值。
Set.prototype[@@iterator]() 返回一个新的迭代器对象,该对象包含 Set 对象中的按插入顺序排列的所有元素的值。

示例

const s = new Set([3, 3, 3, 2, 2, 1]);

console.log(s); // Set(3) {3, 2, 1}

s.add(3);
console.log(s); // Set(3) {3, 2, 1}

const setIterator = s[Symbol.iterator]();
console.log(setIterator); // SetIterator {3, 2, 1}

let arr = [3, 3, 3, 2, 2, 1];
arr = [...new Set(arr).keys()]; // 去重
console.log(arr); // (3) [3, 2, 1]

WeakSet

描述

WeakSet 的值只能是 Object 类型,持有的是 Object 弱引用,原始数据类型不能作为值。 WeakSet 持有的是对象的弱引用,这意味着在没有其他引用存在时垃圾回收能正确进行, WeakSet 用于存储的对象引用只有在其没有被回收时才是有效的,正由于弱引用, WeakSet 是不可枚举的。
简单来说,有时需要在某个数组上面存放一些对象,但是这会形成对于这个对象的引用,一旦不再需要这个对象,我们就必须手动删除这个引用,否则垃圾回收机制无法释放对象占用的内存, WeakSet 的设计就是解决这个问题的,其所引用的对象都是弱引用,垃圾回收机制不将该引用考虑在内,因此,只要所引用的对象的其他引用都被清除,垃圾回收机制就会释放该对象所占用的内存,此时 WeakSet 里边所对应的对象引用会消失,不需要手动删除引用。如果需要在数组上添加对象而又不想干扰垃圾回收机制的话,就可以使用 WeakSet ,此外 WeakSet 非常适合于对象引用的跟踪,尤其是在涉及大量对象时。

属性与方法

属性和方法 功能
WeakSet.prototype.constructor 返回构造函数。
WeakSet.prototype.add(value) 在该 WeakSet 对象中添加一个新元素 value
WeakSet.prototype.delete(value) 从该 WeakSet 对象中删除 value 这个元素。
WeakSet.prototype.has(value) 返回一个布尔值,表示给定的值 value 是否存在于这个 WeakSet 中。

内存回收实例

WeakSet 示例

const ws = new WeakSet();
let value = new Array(6 * 1024 * 1024); // 开辟一个大数组
ws.add(value);
console.log(ws.has(value)); // true
value = null; // 解除应用
console.log(ws.has(value)); // false

WeakSet 内存回收

/** node --expose-gc **/ // 启动 node 环境 手动调用垃圾回收机制
global.gc(); // 首先调用一次垃圾回收
process.memoryUsage(); // 查看内存占用 heapUsed 约 3M
/*
{
  rss: 24272896,
  heapTotal: 5222400,
  heapUsed: 3124632,
  external: 1568727,
  arrayBuffers: 140472
}
*/
const ws = new WeakSet();
let value = new Array(6 * 1024 * 1024); // 开辟一个大数组 
ws.add(value);
console.log(ws.has(value)); // true
process.memoryUsage(); // heapUsed 约 53M
/*
{
  rss: 75153408,
  heapTotal: 55558144,
  heapUsed: 53554632,
  external: 1568730,
  arrayBuffers: 337083
}
*/
global.gc(); // 手动执行一次垃圾回收
process.memoryUsage(); // heapUsed 约 53M
/*
{
  rss: 75390976,
  heapTotal: 55558144,
  heapUsed: 53376552,
  external: 1568728,
  arrayBuffers: 378041
}
*/
value = null; // 解除引用
global.gc(); // 执行垃圾回收
process.memoryUsage(); // heapUsed 约 3M 内存已回收
/*
{
  rss: 25178112,
  heapTotal: 5222400,
  heapUsed: 3063152,
  external: 1568731,
  arrayBuffers: 435388
}
*/
console.log(ws.has(value)); // false

Set 示例

const s = new Set();
let value = new Array(6 * 1024 * 1024); // 开辟一个大数组 
s.add(value);
console.log(s.has(value)); // true
value = null; // 解除引用
console.log(s.has(value)); // false
console.log(s); // Set(1) {Array(6291456)}
s.clear(); // 回收内存
console.log(s); // Set(0) {}

Set 内存回收

/** node --expose-gc **/ // 启动 node 环境 手动调用垃圾回收机制
global.gc(); // 首先调用一次垃圾回收
process.memoryUsage(); // 查看内存占用 heapUsed 约 3M
/*
{
  rss: 24641536,
  heapTotal: 5222400,
  heapUsed: 3475568,
  external: 1568695,
  arrayBuffers: 115904
}
*/
const s = new Set();
let value = new Array(6 * 1024 * 1024); // 开辟一个大数组 
s.add(value);
console.log(s.has(value)); // true
process.memoryUsage(); // heapUsed 约 53M
/*
{
  rss: 75141120,
  heapTotal: 55558144,
  heapUsed: 53454992,
  external: 1568730,
  arrayBuffers: 304315
}
*/
global.gc(); // 手动执行一次垃圾回收
process.memoryUsage(); // heapUsed 约 53M
/*
{
  rss: 75235328,
  heapTotal: 55558144,
  heapUsed: 53384240,
  external: 1568728,
  arrayBuffers: 320697
}
*/
value = null; // 解除引用
global.gc(); // 执行垃圾回收
process.memoryUsage(); // heapUsed 仍为 53M 内存未回收
/*
{
  rss: 75243520,
  heapTotal: 55558144,
  heapUsed: 53461528,
  external: 1568737,
  arrayBuffers: 369858
}
*/
console.log(s.has(value)); // false // 此处为 false,这是因为 value 值的改变,而在这个 Set 实例对象中依然存在对 Array 的强引用,内存未回收
console.log(s); // Set(1) {Array(6291456)}
s.clear(); // 回收内存
global.gc(); // 执行垃圾回收
process.memoryUsage(); // heapUsed 约 2M 内存已回收
/*
{
  rss: 25055232,
  heapTotal: 5222400,
  heapUsed: 3167016,
  external: 1568737,
  arrayBuffers: 541890
}
*/
console.log(s); // Set(0) {}

转载规则

《Set 与 WeakSet》Konata 采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。
  目录