|

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:

FeatureSetArray
Duplicates❌ Never✅ Allowed
OrderInsertionIndexed
Lookup by valueset.has(x) — O(1)arr.includes(x) — O(n)
Access by indexarr[i]
Sizeset.sizearr.length
IterationDirectly iterableDirectly iterable
Addset.add(x)arr.push(x)
Removeset.delete(x)arr.splice(...)
JSONNot directlyJSON.stringify

When to use a Set:

  • You need uniqueness — deduplication, tags, IDs
  • You need fast membership checkshas() 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 accessarr[0]
  • You need ordered duplicates — multiple same values
  • You need JSON serialization directly
  • You need array methodsmap, 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:

MethodPurposeReturns
set.add(value)Add a valueThe Set
set.has(value)Check membershipBoolean
set.delete(value)Remove a valueBoolean (found?)
set.clear()Remove everythingundefined
set.sizeCount (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:

MethodYields
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:

FeatureSetWeakSet
HoldsAny valueObjects only
Sizeset.sizeNot available
Iteration
forEach
Garbage collectionPreventsAllows
Methodsadd, has, delete, clearadd, has, delete
OrderNot 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:

FeatureWeakSetWeakMap
KeysObjectsObjects
ValuesAny
StoresObject membershipObject → value
Use caseTaggingMetadata

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

MethodPurposeReturns
new Set(iterable)CreateSet
set.add(v)AddSet
set.has(v)CheckBoolean
set.delete(v)RemoveBoolean
set.clear()Remove allundefined
set.sizeCountNumber

Set Iteration

MethodYields
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

OperationCode
Unionnew Set([...a, ...b])
Intersectionnew Set([...a].filter(x => b.has(x)))
Differencenew Set([...a].filter(x => !b.has(x)))
Symmetric differencenew Set([...a].filter(x => !b.has(x)).concat([...b].filter(x => !a.has(x))))
Subset[...a].every(x => b.has(x))

Set vs Array

FeatureSetArray
Duplicates
Index access
has speedO(1)O(n)
map/filter
JSONManualDirect
OrderInsertionIndexed

WeakSet

FeatureWeakSet
HoldsObjects only
Size
Iteration
GCWeak
Methodsadd, has, delete
Use caseTagging, brands

Set vs WeakSet

FeatureSetWeakSet
ValuesAnyObjects
Size
Iteration
clear
GCStrongWeak
Deterministic

Common Patterns

PatternCode
Dedupe[...new Set(arr)]
Unique countnew Set(arr).size
Membershipset.has(x)
Unionnew Set([...a, ...b])
Intersectionnew Set([...a].filter(x => b.has(x)))
Remove itemsarr.filter(x => !remove.has(x))
Track visitedif (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

PitfallProblemSolution
size()TypeErrorUse .size property
set[0]undefinedIterate with for...of
JSON.stringify(set)"{}"[...set] first
Object referencesNew objects not equalStore the reference
WeakSet primitivesTypeErrorObjects only
WeakSet iterationTypeErrorNot iterable
WeakSet sizeundefinedNot available
NaN in array dedupeindexOf failsUse Set
set.mapNot a methodConvert to array first
+0 vs -0Treated as sameSameValueZero

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

ConceptSyntaxExample
Createnew Set()const s = new Set()
From iterablenew Set(iterable)new Set([1, 2, 2])
Adds.add(v)s.add(1)
Checks.has(v)s.has(1)
Deletes.delete(v)s.delete(1)
Clears.clear()s.clear()
Sizes.sizeconsole.log(s.size)
Iteratefor (const v of s)Values
To array[...s][1, 2, 3]
Unionnew 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
WeakSetnew WeakSet()Objects only
WeakSet addws.add(obj)Tag object
WeakSet hasws.has(obj)Brand check

Key takeaways:

  • Set stores unique values in insertion order — no duplicates, fast has
  • add, has, delete, clear, size — the entire Set API
  • Use [...new Set(arr)] to deduplicate in one line
  • Use has for 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)
  • Set treats NaN as equal to itself and +0/-0 as the same
  • Objects are compared by reference — two {a: 1} are different entries
  • WeakSet holds 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!