WeakSet
) ES6 (advanced)
WeakSets are similar to Sets, with the following differences:
They can hold objects without preventing those objects from being garbage-collected.
They are black boxes: we only get any data out of a WeakSet if we have both the WeakSet and a value. The only methods that are supported are .add()
, .delete()
, .has()
. See the section on WeakMaps as black boxes for an explanation of why WeakSets don’t allow iteration, looping, and clearing.
Given that we can’t iterate over the elements of WeakSets, there are not that many use cases for them.
We can use WeakSets to mark objects – for example:
const isSaved = new WeakSet();
{
const obj = {};
isSaved.add(obj); // (A)
assert.equal(
isSaved.has(obj), // (B)
true
);
}
// (C)
obj
as saved.
obj
is saved.
obj
can be garbage-collected even though it is an element of the data structure isSaved
.
In a way, we created a boolean property for obj
, but stored it externally. If isSaved
were a property, the previous code would look as follows:
{
const obj = {};
obj.isSaved = true;
assert.equal(
obj.isSaved,
true
);
}
The following code demonstrates how a class can ensure that its methods are only applied to instances that were created by it (based on code by Domenic Denicola):
const instancesOfSafeClass = new WeakSet();
class SafeClass {
constructor() {
instancesOfSafeClass.add(this);
}
method() {
if (!instancesOfSafeClass.has(this)) {
throw new TypeError('Incompatible object!');
}
}
}
const safeInstance = new SafeClass();
safeInstance.method(); // works
assert.throws(
() => {
const obj = {};
SafeClass.prototype.method.call(obj); // throws an exception
},
TypeError
);
The constructor and the three methods of WeakSet
work the same as their Set
equivalents:
new WeakSet<T>(values?: Iterable<T>)
ES6
.add(value: T): this
ES6
.delete(value: T): boolean
ES6
.has(value: T): boolean
ES6