WeakSet features
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
- Can only store object references: WeakSet can only contain object values, not primitive values.
- Non-iterable: WeakSet does not have a
size
property and cannot be traversed usingfor...of
. - 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
- Non-iterable: Cannot retrieve all values in a WeakSet.
- No
size
property: Cannot determine the number of elements in a WeakSet. - 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:
- No need to manually clean up unnecessary references.
- The garbage collector automatically handles unreferenced objects.
- 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