JavaScript 47 🧬 Sets and WeakSets
const set = new Set();
set.add(1);
set.add(2);
set.add(2);
console.log(set.size);
console.log(set.has(1));
console.log(set.has(3));
set.delete(1);
console.log(set.size);
set.clear();
console.log(set.size);
const fromArray = new Set([1, 2, 2, 3, 3, 3]);
console.log([...fromArray]);
for (const value of fromArray) {
console.log(value);
}
const weakSet = new WeakSet();
let obj = { id: 1 };
weakSet.add(obj);
console.log(weakSet.has(obj));
weakSet.delete(obj);
console.log(weakSet.has(obj));
A Set is a collection of unique values. Unlike arrays, it never allows duplicates and provides fast lookup with .has(). A WeakSet is a special variant that only holds objects and lets them be garbage-collected when no other references remain.
Key point: Use Set when you need uniqueness or fast membership checks on primitives. Use WeakSet when you need to tag objects without preventing their garbage collection. Sets preserve insertion order and can hold any type — primitives, objects, even other Sets.
a – What is a Set and when to use it
A Set is an ordered collection of unique values — no duplicates, ever.
Creating a Set:
const set = new Set();
Or from an iterable:
const fromArray = new Set([1, 2, 2, 3, 3, 3]);
console.log(fromArray);
// [ Set(3) { 1, 2, 3 } ]
Duplicates are silently dropped.
Set vs Array — the key differences:
| Feature | Set | Array |
|---|---|---|
| Duplicates | ❌ Never | ✅ Allowed |
| Order | Insertion | Indexed |
| Lookup by value | set.has(x) — O(1) | arr.includes(x) — O(n) |
| Access by index | ❌ | arr[i] |
| Size | set.size | arr.length |
| Iteration | Directly iterable | Directly iterable |
| Add | set.add(x) | arr.push(x) |
| Remove | set.delete(x) | arr.splice(...) |
| JSON | Not directly | JSON.stringify |
When to use a Set:
- You need uniqueness — deduplication, tags, IDs
- You need fast membership checks —
has()is O(1) - You track visited items — graphs, trees, BFS
- You need set operations — union, intersection, difference
- You want to know if something was seen without storing order
When to use an Array:
- You need indexed access —
arr[0] - You need ordered duplicates — multiple same values
- You need JSON serialization directly
- You need array methods —
map,filter,reduce
The classic Set use case — deduplication:
const dupes = [1, 2, 2, 3, 3, 3];
const unique = [...new Set(dupes)];
console.log(unique);
// [ [ 1, 2, 3 ] ]
One line, no loop. This is the most common use of Set.
Fast membership — the other big win:
const banned = new Set(['spam', 'scam', 'phishing']);
function isBanned(word) {
return banned.has(word); // O(1)
}
Versus array lookup — O(n):
const bannedArr = ['spam', 'scam', 'phishing'];
bannedArr.includes('scam'); // scans the whole array
For small lists it doesn’t matter. For thousands of items, Set wins big.
Sets can hold any type:
const set = new Set();
set.add(1);
set.add('one');
set.add(true);
set.add(null);
set.add(undefined);
set.add({});
set.add([1, 2, 3]);
set.add(new Date());
console.log(set.size);
// [ 8 ]
Objects and arrays are compared by reference:
const set = new Set();
set.add({ a: 1 });
set.add({ a: 1 }); // different reference
console.log(set.size);
// [ 2 ]
const obj = { a: 1 };
set.add(obj);
set.add(obj); // same reference
console.log(set.size);
// [ 3 ]
Special value equality:
Sets use the SameValueZero algorithm — like === but NaN equals itself:
const set = new Set([NaN, NaN]);
console.log(set.size);
// [ 1 ] ← NaN deduplicated
const set2 = new Set([+0, -0]);
console.log(set2.size);
// [ 1 ] ← +0 and -0 treated as equal
Sets preserve insertion order:
const set = new Set(['c', 'a', 'b']);
console.log([...set]);
// [ [ 'c', 'a', 'b' ] ]
Unlike object keys, Sets don’t reorder anything.
b – Set methods and iteration
A Set has a small, focused API — plus all the standard iteration patterns.
Core methods:
| Method | Purpose | Returns |
|---|---|---|
set.add(value) | Add a value | The Set |
set.has(value) | Check membership | Boolean |
set.delete(value) | Remove a value | Boolean (found?) |
set.clear() | Remove everything | undefined |
set.size | Count (property) | Number |
add — add a value:
const set = new Set();
set.add(1);
set.add(2);
set.add(1); // ignored — already exists
console.log(set);
// [ Set(2) { 1, 2 } ]
add returns the Set, so you can chain:
set.add(1).add(2).add(3);
has — check membership:
const set = new Set([1, 2, 3]);
console.log(set.has(2));
// [ true ]
console.log(set.has(99));
// [ false ]
has is O(1) — constant time regardless of Set size.
delete — remove a value:
const set = new Set([1, 2, 3]);
console.log(set.delete(2));
// [ true ]
console.log(set.delete(99));
// [ false ]
Returns true if the value was present, false otherwise.
clear — remove all:
const set = new Set([1, 2, 3]);
set.clear();
console.log(set.size);
// [ 0 ]
size — count entries:
const set = new Set([1, 2, 3]);
console.log(set.size);
// [ 3 ]
size is a property, not a method.
Iteration methods:
| Method | Yields |
|---|---|
for (const v of set) | Values |
set.keys() | Values (same as values) |
set.values() | Values |
set.entries() | [value, value] pairs |
set.forEach(fn) | (value, value, set) |
Iterating with for...of:
const set = new Set(['a', 'b', 'c']);
for (const value of set) {
console.log(value);
}
// [ a ]
// [ b ]
// [ c ]
keys() and values() are identical for Sets:
const set = new Set([1, 2, 3]);
console.log([...set.keys()]);
// [ [ 1, 2, 3 ] ]
console.log([...set.values()]);
// [ [ 1, 2, 3 ] ]
Set has both methods for API compatibility with Map.
entries() yields [value, value] pairs:
const set = new Set(['a', 'b']);
console.log([...set.entries()]);
// [ [ [ 'a', 'a' ], [ 'b', 'b' ] ] ]
Again, for Map compatibility — destructuring [k, v] still works:
for (const [k, v] of set.entries()) {
console.log(k, v);
}
// [ a a ]
// [ b b ]
forEach:
const set = new Set([1, 2, 3]);
set.forEach((value, value2, set) => {
console.log(value);
});
// [ 1 ]
// [ 2 ]
// [ 3 ]
The first two arguments are both the value — Map compatibility again.
Converting a Set to an array:
const set = new Set([1, 2, 3]);
const arr = [...set];
console.log(arr);
// [ [ 1, 2, 3 ] ]
// Or:
const arr2 = Array.from(set);
Converting a Set to a string:
const set = new Set([1, 2, 3]);
console.log([...set].join(', '));
// [ '1, 2, 3' ]
console.log(JSON.stringify([...set]));
// [ '[1,2,3]' ]
Set has no map or filter:
Unlike arrays, Sets don’t have map, filter, or reduce. Convert to an array first:
const set = new Set([1, 2, 3, 4]);
const doubled = new Set([...set].map(x => x * 2));
console.log(doubled);
// [ Set(4) { 2, 4, 6, 8 } ]
const evens = new Set([...set].filter(x => x % 2 === 0));
console.log(evens);
// [ Set(2) { 2, 4 } ]
Set operations — union, intersection, difference:
const a = new Set([1, 2, 3]);
const b = new Set([3, 4, 5]);
// Union
const union = new Set([...a, ...b]);
console.log(union);
// [ Set(5) { 1, 2, 3, 4, 5 } ]
// Intersection
const intersection = new Set([...a].filter(x => b.has(x)));
console.log(intersection);
// [ Set(1) { 3 } ]
// Difference (in a, not in b)
const difference = new Set([...a].filter(x => !b.has(x)));
console.log(difference);
// [ Set(2) { 1, 2 } ]
// Symmetric difference (in either, not both)
const symmetric = new Set([
...[...a].filter(x => !b.has(x)),
...[...b].filter(x => !a.has(x))
]);
console.log(symmetric);
// [ Set(4) { 1, 2, 4, 5 } ]
// Subset check
const isSubset = [...a].every(x => b.has(x));
console.log(isSubset);
// [ false ]
Built-in Set methods (ES2025 — very new):
Modern engines now support union, intersection, difference, symmetricDifference, isSubsetOf, isSupersetOf, isDisjointFrom:
const a = new Set([1, 2, 3]);
const b = new Set([3, 4, 5]);
console.log(a.union(b));
// [ Set(5) { 1, 2, 3, 4, 5 } ]
console.log(a.intersection(b));
// [ Set(1) { 3 } ]
console.log(a.difference(b));
// [ Set(2) { 1, 2 } ]
console.log(a.symmetricDifference(b));
// [ Set(4) { 1, 2, 4, 5 } ]
console.log(a.isSubsetOf(b));
// [ false ]
console.log(a.isSupersetOf(b));
// [ false ]
console.log(a.isDisjointFrom(b));
// [ false ]
Note: These are very recent (ES2025). Check browser/Node support before relying on them.
Common Set patterns:
Deduplicate strings:
const tags = ['js', 'node', 'js', 'react', 'node'];
const unique = [...new Set(tags)];
// [ [ 'js', 'node', 'react' ] ]
Track visited nodes in a graph:
function bfs(start) {
const visited = new Set();
const queue = [start];
while (queue.length) {
const node = queue.shift();
if (visited.has(node)) continue;
visited.add(node);
queue.push(...node.neighbors);
}
return visited;
}
Fast lookup for allow-lists:
const allowed = new Set(['png', 'jpg', 'gif']);
if (allowed.has(ext)) {
// process
}
Remove items from an array:
const arr = [1, 2, 3, 4, 5];
const remove = new Set([2, 4]);
const result = arr.filter(x => !remove.has(x));
// [ [ 1, 3, 5 ] ]
Count unique words:
const text = 'the cat in the hat';
const uniqueWords = new Set(text.split(' '));
console.log(uniqueWords.size);
// [ 4 ]
Find duplicates in an array:
const arr = [1, 2, 3, 2, 4, 1];
const seen = new Set();
const dupes = new Set();
for (const x of arr) {
if (seen.has(x)) dupes.add(x);
else seen.add(x);
}
console.log([...dupes]);
// [ [ 2, 1 ] ]
c – WeakSet
A WeakSet is like a Set, but with fewer features and a very specific purpose: it holds weak references to objects, letting them be garbage-collected when nothing else references them.
Key properties:
| Feature | Set | WeakSet |
|---|---|---|
| Holds | Any value | Objects only |
| Size | set.size | Not available |
| Iteration | ✅ | ❌ |
forEach | ✅ | ❌ |
| Garbage collection | Prevents | Allows |
| Methods | add, has, delete, clear | add, has, delete |
| Order | ✅ | Not guaranteed |
Why WeakSet exists:
WeakSets let you tag objects — mark that they’ve been seen, processed, or belong to a group — without keeping them alive. Once no other reference to the object exists, it and its WeakSet entry disappear together. No memory leaks.
Creating a WeakSet:
const weakSet = new WeakSet();
Adding and checking:
let obj = { id: 1 };
weakSet.add(obj);
console.log(weakSet.has(obj));
// [ true ]
Deleting:
weakSet.delete(obj);
console.log(weakSet.has(obj));
// [ false ]
No size, no iteration:
console.log(weakSet.size);
// [ undefined ]
for (const x of weakSet) { }
// TypeError: weakSet is not iterable
You cannot enumerate a WeakSet — because its contents could change at any time due to garbage collection.
Garbage collection demo:
const weakSet = new WeakSet();
let obj = { id: 1 };
weakSet.add(obj);
console.log(weakSet.has(obj));
// [ true ]
obj = null; // now the object is unreferenced
// ... at some point, garbage collector reclaims it
// weakSet.has(obj) — but we no longer have obj
You can’t observe the collection directly — it happens invisibly.
Objects only:
const ws = new WeakSet();
ws.add({}); // ✅
ws.add([]); // ✅
ws.add(function(){}); // ✅
ws.add(1); // ❌ TypeError: Invalid value used in weak set
ws.add('str'); // ❌ TypeError
ws.add(null); // ❌ TypeError
ws.add(undefined); // ❌ TypeError
WeakSets reject primitives — they only work with objects.
Common WeakSet use cases:
Pattern 1 — Track processed objects:
const processed = new WeakSet();
function process(obj) {
if (processed.has(obj)) return;
processed.add(obj);
// ... process obj
}
No need to remove entries — GC handles it when the object dies.
Pattern 2 — Prevent infinite recursion in graphs:
const visited = new WeakSet();
function walk(node) {
if (visited.has(node)) return;
visited.add(node);
console.log(node.name);
node.children?.forEach(walk);
}
Pattern 3 — Tag DOM elements:
const initialized = new WeakSet();
function initElement(el) {
if (initialized.has(el)) return;
initialized.add(el);
el.addEventListener('click', handleClick);
}
When the DOM element is removed, the WeakSet entry disappears too.
Pattern 4 — Mark data as “owned” by a class:
const priv = new WeakSet();
class Secret {
constructor() {
priv.add(this);
}
reveal() {
if (!priv.has(this)) throw new Error('Not a Secret');
return 'the secret';
}
}
This is a brand check — verifying an object was created by a specific constructor.
Pattern 5 — Metadata attached to objects:
const meta = new WeakSet();
function tag(obj) {
meta.add(obj);
}
function isTagged(obj) {
return meta.has(obj);
}
WeakSet vs WeakMap:
| Feature | WeakSet | WeakMap |
|---|---|---|
| Keys | Objects | Objects |
| Values | — | Any |
| Stores | Object membership | Object → value |
| Use case | Tagging | Metadata |
WeakSet stores only objects (no values). WeakMap stores object → value pairs. Both use weak references so keys don’t leak.
Limitations of WeakSet:
- ❌ No
size - ❌ No iteration
- ❌ No
forEach - ❌ No
clear() - ❌ Objects only — no primitives
- ⚠️ Non-deterministic — you can’t observe when entries disappear
When to use WeakSet:
- You need to tag objects without preventing GC
- You want to avoid memory leaks in long-running apps
- You’re implementing a brand check for a class
- You’re tracking visited objects during traversal
- You want a membership test for objects only
When to use Set instead:
- You need to iterate or get size
- You need to store primitives
- You need to clear all entries
Complete Example Session
// ============================================
// PART 1: CREATE A SET
// ============================================
const set = new Set();
set.add(1);
set.add(2);
set.add(2);
console.log(set);
// [ Set(2) { 1, 2 } ]
// ============================================
// PART 2: SIZE
// ============================================
console.log(set.size);
// [ 2 ]
// ============================================
// PART 3: HAS
// ============================================
console.log(set.has(1));
// [ true ]
console.log(set.has(3));
// [ false ]
// ============================================
// PART 4: DELETE
// ============================================
set.delete(1);
console.log(set.size);
// [ 1 ]
// ============================================
// PART 5: CLEAR
// ============================================
set.clear();
console.log(set.size);
// [ 0 ]
// ============================================
// PART 6: FROM ARRAY
// ============================================
const fromArray = new Set([1, 2, 2, 3, 3, 3]);
console.log(fromArray);
// [ Set(3) { 1, 2, 3 } ]
// ============================================
// PART 7: TO ARRAY
// ============================================
console.log([...fromArray]);
// [ [ 1, 2, 3 ] ]
// ============================================
// PART 8: ITERATE
// ============================================
for (const value of fromArray) {
console.log(value);
}
// [ 1 ]
// [ 2 ]
// [ 3 ]
// ============================================
// PART 9: FOREACH
// ============================================
fromArray.forEach(v => console.log(v));
// [ 1 ]
// [ 2 ]
// [ 3 ]
// ============================================
// PART 10: UNION
// ============================================
const a = new Set([1, 2, 3]);
const b = new Set([3, 4, 5]);
console.log(new Set([...a, ...b]));
// [ Set(5) { 1, 2, 3, 4, 5 } ]
// ============================================
// PART 11: INTERSECTION
// ============================================
console.log(new Set([...a].filter(x => b.has(x))));
// [ Set(1) { 3 } ]
// ============================================
// PART 12: DIFFERENCE
// ============================================
console.log(new Set([...a].filter(x => !b.has(x))));
// [ Set(2) { 1, 2 } ]
// ============================================
// PART 13: DEDUPE ARRAY
// ============================================
const dupes = [1, 2, 2, 3, 3, 3];
console.log([...new Set(dupes)]);
// [ [ 1, 2, 3 ] ]
// ============================================
// PART 14: NAN DEDUPLICATION
// ============================================
console.log(new Set([NaN, NaN]).size);
// [ 1 ]
// ============================================
// PART 15: OBJECT REFERENCES
// ============================================
const objSet = new Set();
objSet.add({ a: 1 });
objSet.add({ a: 1 });
console.log(objSet.size);
// [ 2 ]
const obj = { a: 1 };
objSet.add(obj);
objSet.add(obj);
console.log(objSet.size);
// [ 3 ]
// ============================================
// PART 16: WEAKSET BASICS
// ============================================
const weakSet = new WeakSet();
let obj47 = { id: 1 };
weakSet.add(obj47);
console.log(weakSet.has(obj47));
// [ true ]
weakSet.delete(obj47);
console.log(weakSet.has(obj47));
// [ false ]
// ============================================
// PART 17: WEAKSET REJECTS PRIMITIVES
// ============================================
try {
weakSet.add(1);
} catch (err) {
console.log(err.message);
}
// [ Invalid value used in weak set ]
// ============================================
// PART 18: WEAKSET NO SIZE
// ============================================
console.log(weakSet.size);
// [ undefined ]
// ============================================
// PART 19: WEAKSET NOT ITERABLE
// ============================================
try {
for (const x of weakSet) {}
} catch (err) {
console.log(err.message);
}
// [ weakSet is not iterable ]
// ============================================
// PART 20: FULL SCRIPT
// ============================================
const set47 = new Set();
set47.add(1);
set47.add(2);
set47.add(2);
console.log(set47.size);
console.log(set47.has(1));
console.log(set47.has(3));
set47.delete(1);
console.log(set47.size);
set47.clear();
console.log(set47.size);
const fromArray47 = new Set([1, 2, 2, 3, 3, 3]);
console.log([...fromArray47]);
for (const value of fromArray47) {
console.log(value);
}
const weakSet47 = new WeakSet();
let obj47b = { id: 1 };
weakSet47.add(obj47b);
console.log(weakSet47.has(obj47b));
weakSet47.delete(obj47b);
console.log(weakSet47.has(obj47b));
Quick Reference
Set Methods
| Method | Purpose | Returns |
|---|---|---|
new Set(iterable) | Create | Set |
set.add(v) | Add | Set |
set.has(v) | Check | Boolean |
set.delete(v) | Remove | Boolean |
set.clear() | Remove all | undefined |
set.size | Count | Number |
Set Iteration
| Method | Yields |
|---|---|
for (const v of set) | Values |
set.keys() | Values |
set.values() | Values |
set.entries() | [v, v] pairs |
set.forEach(fn) | (v, v, set) |
Set Operations
| Operation | Code |
|---|---|
| Union | new Set([...a, ...b]) |
| Intersection | new Set([...a].filter(x => b.has(x))) |
| Difference | new Set([...a].filter(x => !b.has(x))) |
| Symmetric difference | new Set([...a].filter(x => !b.has(x)).concat([...b].filter(x => !a.has(x)))) |
| Subset | [...a].every(x => b.has(x)) |
Set vs Array
| Feature | Set | Array |
|---|---|---|
| Duplicates | ❌ | ✅ |
| Index access | ❌ | ✅ |
has speed | O(1) | O(n) |
map/filter | ❌ | ✅ |
| JSON | Manual | Direct |
| Order | Insertion | Indexed |
WeakSet
| Feature | WeakSet |
|---|---|
| Holds | Objects only |
| Size | ❌ |
| Iteration | ❌ |
| GC | Weak |
| Methods | add, has, delete |
| Use case | Tagging, brands |
Set vs WeakSet
| Feature | Set | WeakSet |
|---|---|---|
| Values | Any | Objects |
| Size | ✅ | ❌ |
| Iteration | ✅ | ❌ |
clear | ✅ | ❌ |
| GC | Strong | Weak |
| Deterministic | ✅ | ❌ |
Common Patterns
| Pattern | Code |
|---|---|
| Dedupe | [...new Set(arr)] |
| Unique count | new Set(arr).size |
| Membership | set.has(x) |
| Union | new Set([...a, ...b]) |
| Intersection | new Set([...a].filter(x => b.has(x))) |
| Remove items | arr.filter(x => !remove.has(x)) |
| Track visited | if (visited.has(n)) return; visited.add(n) |
Best Practices
✅ Do This:
// Use Set for deduplication
const unique = [...new Set(arr)]; // ✅
// Use has for fast membership
if (allowed.has(ext)) { ... } // ✅
// Use Set to track visited
const visited = new Set(); // ✅
// Use for...of to iterate
for (const v of set) { ... } // ✅
// Convert to array for array methods
[...set].map(x => x * 2); // ✅
// Use WeakSet for object tagging
const processed = new WeakSet(); // ✅
// Use WeakSet for brand checks
if (!priv.has(this)) throw new Error(); // ✅
// Check size with .size
set.size; // ✅ (not a method)
❌ Don’t Do This:
// Don't use size as a method
set.size(); // ❌ it's a property
// Don't expect JSON.stringify to work
JSON.stringify(new Set([1, 2])); // ❌ returns "{}"
JSON.stringify([...new Set([1, 2])]); // ✅
// Don't use Set for indexed access
set[0]; // ❌ undefined
// Don't add primitives to WeakSet
new WeakSet().add(1); // ❌ TypeError
// Don't iterate a WeakSet
for (const x of new WeakSet()) {} // ❌ TypeError
// Don't rely on WeakSet size
new WeakSet().size; // ❌ undefined
// Don't add two objects thinking they're equal
set.add({ a: 1 });
set.add({ a: 1 }); // ❌ 2 entries
// Don't use Set where array methods are needed
new Set([1, 2]).map(x => x * 2); // ❌ no map
Common Pitfalls
| Pitfall | Problem | Solution |
|---|---|---|
size() | TypeError | Use .size property |
set[0] | undefined | Iterate with for...of |
JSON.stringify(set) | "{}" | [...set] first |
| Object references | New objects not equal | Store the reference |
| WeakSet primitives | TypeError | Objects only |
| WeakSet iteration | TypeError | Not iterable |
| WeakSet size | undefined | Not available |
NaN in array dedupe | indexOf fails | Use Set |
set.map | Not a method | Convert to array first |
+0 vs -0 | Treated as same | SameValueZero |
Real-World Examples
1. Dedupe Array
const arr = [1, 2, 2, 3, 3, 3];
console.log([...new Set(arr)]);
// [ [ 1, 2, 3 ] ]
2. Count Unique
const words = ['a', 'b', 'a', 'c', 'b'];
console.log(new Set(words).size);
// [ 3 ]
3. Fast Membership
const allowed = new Set(['png', 'jpg', 'gif']);
console.log(allowed.has('png'));
// [ true ]
4. Iterate Set
const set = new Set(['a', 'b', 'c']);
for (const v of set) console.log(v);
// [ a ]
// [ b ]
// [ c ]
5. Union
const a = new Set([1, 2]);
const b = new Set([2, 3]);
console.log([...new Set([...a, ...b])]);
// [ [ 1, 2, 3 ] ]
6. Intersection
const a = new Set([1, 2, 3]);
const b = new Set([2, 3, 4]);
console.log([...a].filter(x => b.has(x)));
// [ [ 2, 3 ] ]
7. Difference
const a = new Set([1, 2, 3]);
const b = new Set([2, 3, 4]);
console.log([...a].filter(x => !b.has(x)));
// [ [ 1 ] ]
8. Remove From Array
const arr = [1, 2, 3, 4, 5];
const remove = new Set([2, 4]);
console.log(arr.filter(x => !remove.has(x)));
// [ [ 1, 3, 5 ] ]
9. Track Visited in BFS
function bfs(start) {
const visited = new Set();
const queue = [start];
while (queue.length) {
const node = queue.shift();
if (visited.has(node)) continue;
visited.add(node);
queue.push(...(node.children || []));
}
return visited;
}
10. Find Duplicates
const arr = [1, 2, 3, 2, 4, 1];
const seen = new Set();
const dupes = new Set();
for (const x of arr) {
if (seen.has(x)) dupes.add(x);
else seen.add(x);
}
console.log([...dupes]);
// [ [ 2, 1 ] ]
11. WeakSet Basic
const weakSet = new WeakSet();
let obj = { id: 1 };
weakSet.add(obj);
console.log(weakSet.has(obj));
// [ true ]
12. WeakSet Tagging
const processed = new WeakSet();
function process(obj) {
if (processed.has(obj)) return;
processed.add(obj);
// ... do work
}
13. WeakSet Brand Check
const priv = new WeakSet();
class Secret {
constructor() { priv.add(this); }
reveal() {
if (!priv.has(this)) throw new Error('Not a Secret');
return 'the secret';
}
}
14. WeakSet for DOM
const initialized = new WeakSet();
function init(el) {
if (initialized.has(el)) return;
initialized.add(el);
el.classList.add('ready');
}
15. Unique Tags
const tags = ['js', 'node', 'js', 'react'];
console.log([...new Set(tags)]);
// [ [ 'js', 'node', 'react' ] ]
16. Set of Objects by Reference
const obj = { id: 1 };
const set = new Set([obj, obj, { id: 1 }]);
console.log(set.size);
// [ 2 ]
17. NaN Deduplication
console.log(new Set([NaN, NaN]).size);
// [ 1 ]
18. Set from String
console.log([...new Set('hello')]);
// [ [ 'h', 'e', 'l', 'o' ] ]
19. Set from Map Keys
const map = new Map([['a', 1], ['b', 2]]);
console.log([...new Set(map.keys())]);
// [ [ 'a', 'b' ] ]
20. Full Script
const set47 = new Set();
set47.add(1);
set47.add(2);
set47.add(2);
console.log(set47.size);
console.log(set47.has(1));
console.log(set47.has(3));
set47.delete(1);
console.log(set47.size);
set47.clear();
console.log(set47.size);
const fromArray47 = new Set([1, 2, 2, 3, 3, 3]);
console.log([...fromArray47]);
for (const value of fromArray47) {
console.log(value);
}
const weakSet47 = new WeakSet();
let obj47b = { id: 1 };
weakSet47.add(obj47b);
console.log(weakSet47.has(obj47b));
weakSet47.delete(obj47b);
console.log(weakSet47.has(obj47b));
Visual: Set vs Array
┌──────────────────────────────────────────────┐
│ Set │
│ │
│ add(1) add(2) add(2) │
│ │ │
│ ▼ │
│ { 1, 2 } ← 2 ignored │
│ │
│ has(2) → O(1) size → 2 │
│ No index access │
│ Iterable │
│ │
└──────────────────────────────────────────────┘
┌──────────────────────────────────────────────┐
│ Array │
│ │
│ push(1) push(2) push(2) │
│ │ │
│ ▼ │
│ [1, 2, 2] ← duplicates allowed │
│ │
│ includes(2) → O(n) length → 3 │
│ arr[0] → 1 │
│ Iterable │
│ │
└──────────────────────────────────────────────┘
Visual: Set Operations
┌──────────────────────────────────────────────┐
│ a = {1, 2, 3} │
│ b = {3, 4, 5} │
│ │
│ Union │
│ {1, 2, 3, 4, 5} │
│ │
│ Intersection │
│ {3} │
│ │
│ Difference (a \ b) │
│ {1, 2} │
│ │
│ Symmetric Difference │
│ {1, 2, 4, 5} │
│ │
└──────────────────────────────────────────────┘
Visual: WeakSet Lifecycle
┌──────────────────────────────────────────────┐
│ const ws = new WeakSet(); │
│ let obj = { id: 1 }; │
│ ws.add(obj); │
│ │
│ ws ─────► obj │
│ (weak reference) │
│ │
│ Other code ─────► obj │
│ (strong reference) │
│ │
│ Both exist → obj alive, ws.has(obj) = true │
│ │
│ Other code releases obj: │
│ obj = null; │
│ │
│ Only ws reference remains: │
│ ws ─ ─ ─► obj (weak, doesn't count) │
│ │
│ Garbage collector reclaims obj → entry gone │
│ │
└──────────────────────────────────────────────┘
Summary
| Concept | Syntax | Example |
|---|---|---|
| Create | new Set() | const s = new Set() |
| From iterable | new Set(iterable) | new Set([1, 2, 2]) |
| Add | s.add(v) | s.add(1) |
| Check | s.has(v) | s.has(1) |
| Delete | s.delete(v) | s.delete(1) |
| Clear | s.clear() | s.clear() |
| Size | s.size | console.log(s.size) |
| Iterate | for (const v of s) | Values |
| To array | [...s] | [1, 2, 3] |
| Union | new Set([...a, ...b]) | Combine |
| Intersection | [...a].filter(x => b.has(x)) | Common |
| Difference | [...a].filter(x => !b.has(x)) | Only in a |
| Dedupe | [...new Set(arr)] | Unique array |
| WeakSet | new WeakSet() | Objects only |
| WeakSet add | ws.add(obj) | Tag object |
| WeakSet has | ws.has(obj) | Brand check |
Key takeaways:
Setstores unique values in insertion order — no duplicates, fasthasadd,has,delete,clear,size— the entire Set API- Use
[...new Set(arr)]to deduplicate in one line - Use
hasfor O(1) membership checks vs O(n)includes - Set has no
map,filter, or index access — convert to array first - Set operations — union, intersection, difference — via spread and filter (or the new ES2025 methods)
SettreatsNaNas equal to itself and+0/-0as the same- Objects are compared by reference — two
{a: 1}are different entries WeakSetholds only objects, uses weak references, and prevents memory leaks- WeakSet has no size, no iteration, no clear — just
add,has,delete - Use WeakSet for tagging, brand checks, and tracking visited objects
- Use
JSON.stringify([...set])— Sets don’t serialize directly
Remember: Sets are the tool for uniqueness and fast membership. Reach for them when you deduplicate, track visited nodes, or check against an allow-list. WeakSets are the specialist — they hold objects without preventing garbage collection, perfect for tagging and brand checks. Master the Set API and Set operations, and half your array-deduplication loops disappear. Choose the right Set for the job and your code stays clean, fast, and leak-free.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!