阿里云主机折上折
  • 微信号
Current Site:Index > WeakSet features

WeakSet features

Author:Chuan Chen 阅读数:12824人阅读 分类: JavaScript

WeakSet is a new collection type introduced in ECMAScript 6, specifically designed to store weak references to objects. Its primary distinction from Set lies in its memory management approach and the resulting limitations in specific usage scenarios.

Basic Characteristics of WeakSet

A WeakSet object allows storing weakly referenced object values, meaning that if there are no other references to an object, it will be automatically reclaimed by the garbage collection mechanism. Objects in a WeakSet are unique and cannot be added repeatedly.

const ws = new WeakSet();
const obj1 = {};
const obj2 = {};

ws.add(obj1);
ws.add(obj2);
console.log(ws.has(obj1)); // true

ws.delete(obj1);
console.log(ws.has(obj1)); // false

Key Differences from Set

  1. Can only store object references: WeakSet can only contain object values, not primitive values.
  2. Non-iterable: WeakSet does not have a size property and cannot be traversed using for...of.
  3. Automatic garbage collection: When an object has no other references, it is automatically removed from the WeakSet.
// Comparison example with Set
const set = new Set();
const ws = new WeakSet();

let obj = {id: 1};

set.add(obj);
ws.add(obj);

obj = null; // Remove reference

// The object is still retained in Set
console.log([...set][0]); // {id: 1}

// The object in WeakSet has been automatically removed
// Cannot verify because WeakSet is not iterable

Use Cases

WeakSet is particularly suitable for scenarios where objects need to be temporarily associated without interfering with garbage collection.

1. Marking Objects

Can be used to mark objects without affecting their lifecycle:

const markedObjects = new WeakSet();

function markObject(obj) {
  markedObjects.add(obj);
}

function isMarked(obj) {
  return markedObjects.has(obj);
}

const user = {name: 'Alice'};
markObject(user);
console.log(isMarked(user)); // true

2. Tracking DOM Elements

Track DOM elements without preventing their reclamation:

const elements = new WeakSet();

const button = document.createElement('button');
elements.add(button);

// When the button is removed from the DOM and garbage collected, it is automatically removed from the WeakSet
document.body.appendChild(button);
document.body.removeChild(button);

Method Details

WeakSet provides three basic methods:

add(value)

Adds an object to the WeakSet:

const ws = new WeakSet();
const obj = {};
ws.add(obj);

has(value)

Checks if an object exists in the WeakSet:

console.log(ws.has(obj)); // true
console.log(ws.has({})); // false

delete(value)

Removes an object from the WeakSet:

ws.delete(obj);
console.log(ws.has(obj)); // false

Considerations

  1. Non-iterable: Cannot retrieve all values in a WeakSet.
  2. No size property: Cannot determine the number of elements in a WeakSet.
  3. Weak reference特性: Stored objects may disappear at any time, making it unsuitable for scenarios requiring stable references.
// The following operations will all cause errors
console.log(ws.size); // undefined
for (let item of ws) {} // TypeError: ws is not iterable
Array.from(ws); // TypeError: ws is not iterable

Practical Application Examples

Preventing Circular References

When dealing with complex object structures, WeakSet can help detect circular references:

function checkCircularReferences(obj) {
  const seen = new WeakSet();
  
  function detect(obj) {
    if (typeof obj === 'object' && obj !== null) {
      if (seen.has(obj)) {
        return true;
      }
      seen.add(obj);
      for (let key in obj) {
        if (detect(obj[key])) {
          return true;
        }
      }
    }
    return false;
  }
  
  return detect(obj);
}

const a = {};
a.self = a;
console.log(checkCircularReferences(a)); // true

Simulating Private Members

WeakSet can be used to simulate private members of a class:

const privateData = new WeakSet();

class Person {
  constructor() {
    privateData.add(this);
  }
  
  isInitialized() {
    return privateData.has(this);
  }
}

const person = new Person();
console.log(person.isInitialized()); // true

Performance Considerations

Due to its use of weak references, WeakSet can be more efficient than Set in certain scenarios:

  1. No need to manually clean up unnecessary references.
  2. The garbage collector automatically handles unreferenced objects.
  3. Suitable for storing large numbers of temporary objects.
// Performance test example
const testObjects = Array(10000).fill(null).map(() => ({}));

// Using Set
console.time('Set');
const set = new Set();
testObjects.forEach(obj => set.add(obj));
console.timeEnd('Set');

// Using WeakSet
console.time('WeakSet');
const ws = new WeakSet();
testObjects.forEach(obj => ws.add(obj));
console.timeEnd('WeakSet');

Browser Compatibility

WeakSet is supported in most modern browsers:

  • Chrome 36+
  • Firefox 34+
  • Edge 12+
  • Safari 9+
  • Opera 23+

In unsupported environments, a polyfill can be used to simulate partial functionality:

// Simple WeakSet polyfill (not fully equivalent)
if (typeof WeakSet === 'undefined') {
  class WeakSet {
    constructor() {
      this._values = [];
    }
    
    add(obj) {
      if (typeof obj !== 'object' || obj === null) {
        throw new TypeError('Invalid value used in weak set');
      }
      this._values.push(new WeakRef(obj));
    }
    
    has(obj) {
      return this._values.some(ref => ref.deref() === obj);
    }
    
    delete(obj) {
      const index = this._values.findIndex(ref => ref.deref() === obj);
      if (index !== -1) {
        this._values.splice(index, 1);
        return true;
      }
      return false;
    }
  }
}

Integration with Other Data Structures

WeakSet can be combined with other ES6 data structures to implement more complex functionality:

// Using with Map
const objectMetadata = new Map();
const trackedObjects = new WeakSet();

function trackObject(obj, metadata) {
  trackedObjects.add(obj);
  objectMetadata.set(obj, metadata);
}

function getMetadata(obj) {
  if (!trackedObjects.has(obj)) return null;
  return objectMetadata.get(obj);
}

const myObj = {};
trackObject(myObj, {created: Date.now()});
console.log(getMetadata(myObj)); // {created: ...}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:Set数据结构

下一篇:与普通对象的比较

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.