JavaScript Sets, Maps & Iterables Explained — Complete Collection Guide
Beyond plain objects and arrays, JavaScript provides specialized collections — Set for unique values, Map for flexible key-value pairs, WeakSet/WeakMap for memory-safe references, and generators for lazy iteration.
What You’ll Learn
- When to use Set vs Array vs Map vs Object
- Set for deduplication and fast lookups
- Map with any key type (objects, numbers, functions)
- WeakSet and WeakMap for memory management
- Custom iterables with Symbol.iterator
- Generator functions for lazy evaluation
Why Collections Matter
Choosing the right collection makes your code faster, cleaner, and less error-prone. Using an object as a key-value store fails when keys aren’t strings. Using an array when you need unique values requires manual deduplication. The Doda Browser uses Maps to store tab metadata (where tab objects are keys) and Sets for unique visited domains. The Durga Antivirus Pro dashboard uses WeakMaps to associate temporary scan data with file objects without preventing garbage collection.
Learning Path
flowchart LR
A[JavaScript Arrays] --> B[JavaScript Objects]
B --> C[Sets, Maps & Iterables]
C --> D[Async JS]
C --> E[JSON]
C --> F[You Are Here]
for...of loops work.Set — Unique Values Only
A Set is like an array that automatically removes duplicates. Think of it as a VIP list — each person can only appear once:
const set = new Set();
set.add(1);
set.add(2);
set.add(2); // Ignored — 2 already exists
set.add(3);
console.log(set.has(1)); // true — O(1) lookup (instant!)
console.log(set.size); // 3 (not 4 — duplicate was ignored)
set.delete(2);
set.clear();Deduplication Trick
const numbers = [1, 2, 2, 3, 3, 3];
const unique = [...new Set(numbers)];
console.log(unique); // [1, 2, 3]
This is the most common use of Set — deduplicate an array in one line. It works with any primitive values and object references.
Map — Keys of Any Type
A Map is like an object but keys can be any type — objects, numbers, functions, even other Maps:
const map = new Map();
map.set('name', 'Alice');
map.set(42, 'answer');
map.set({id: 1}, 'user'); // Object as key!
console.log(map.get('name')); // 'Alice'
console.log(map.has(42)); // true
console.log(map.size); // 3
map.delete(42);Map vs Object
// Object — keys are always strings
const obj = {};
obj[1] = 'one';
obj['1']; // 'one' — same key! Numbers become strings
// Map — preserves key types
const map = new Map();
map.set(1, 'one');
map.set('1', 'another');
map.size; // 2 — different keys
Converting Between Map and Object
// Object → Map
const fromObj = new Map(Object.entries({a: 1, b: 2}));
// Map → Object
const obj = Object.fromEntries(map);WeakSet — Memory-Safe Object References
WeakSet stores only objects (not primitives) and doesn’t prevent garbage collection:
const weakSet = new WeakSet();
let user = { name: 'Alice' };
weakSet.add(user);
console.log(weakSet.has(user)); // true
user = null; // Object removed from weakSet automatically
Why use WeakSet? To “mark” objects without creating memory leaks. For example, to track which files have been scanned by Durga Antivirus Pro — when the file object is no longer needed, the WeakSet entry is automatically cleaned up.
Limitations: WeakSet is not iterable. You can’t get its size, loop over it, or clear it.
WeakMap — Private Data with Auto-Cleanup
WeakMap keys must be objects, and entries are garbage-collected when the key object is no longer referenced:
const weakMap = new WeakMap();
let user = { name: 'Alice' };
weakMap.set(user, 'sensitive data');
user = null; // Entry removed automatically — no memory leak
flowchart LR
A[Strong Reference] -->|Prevents GC| B[Object]
C[Weak Reference] -.->|Allows GC| B
B --> D[Memory freed]
Real-world use: Store private data associated with DOM elements. When an element is removed from the DOM, the WeakMap entry is automatically cleaned up.
Iterables & Custom Iterators
An iterable is any object that has a Symbol.iterator method. Arrays, strings, Maps, and Sets are iterables — that’s why for...of works on them.
You can make your own iterable:
const range = {
from: 1,
to: 5,
[Symbol.iterator]() {
let current = this.from;
const last = this.to;
return {
next() {
return current <= last
? { value: current++, done: false }
: { done: true };
}
};
}
};
for (const n of range) {
console.log(n); // 1, 2, 3, 4, 5
}Line by line:
[Symbol.iterator]()— Defines the iteration behavior as a methodcurrent = this.from— Start at 1next()— Called each iteration. Returns{ value, done }- When
current <= last, return the current value and increment - When past the end, return
{ done: true }to signal completion
Generators
Generator functions (function*) are a simpler way to create iterators. They can pause execution with yield and resume later:
function* countTo(n) {
for (let i = 1; i <= n; i++) {
yield i; // Pause and return i
}
}
const gen = countTo(3);
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }
// Or use with for...of
for (const n of countTo(5)) {
console.log(n); // 1, 2, 3, 4, 5
}Analogy: A generator is like a book with a bookmark. You read a chapter (yield), put the bookmark, and come back later. The book remembers exactly where you stopped.
Infinite Generators
function* fibonacci() {
let a = 0, b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
const fib = fibonacci();
console.log(fib.next().value); // 0
console.log(fib.next().value); // 1
console.log(fib.next().value); // 1
console.log(fib.next().value); // 2
// ...could go forever!
Common Mistakes
1. Using objects as key-value stores when keys aren’t strings
const obj = {};
obj[1] = 'one';
obj['1']; // 'one' — 1 was converted to string '1'!
Fix: Use Map when keys are not plain strings.
2. Assuming Set compares objects by value
const set = new Set();
set.add({id: 1});
set.add({id: 1}); // Different object reference — both added!
console.log(set.size); // 2
Set compares objects by reference, not by value.
3. Trying to add primitives to WeakSet
const ws = new WeakSet();
ws.add(42); // TypeError: Invalid value used in weak set
WeakSet and WeakMap only accept object keys/references.
4. Using .length on Map/Set
const map = new Map();
map.set('a', 1);
console.log(map.length); // undefined
Fix: Use .size (not .length) for Map and Set.
5. Trying to iterate WeakMap or WeakSet
WeakMap and WeakSet are not iterable. You can’t use for...of, get .size, or .clear() them.
Practice Questions
What’s the difference between Set and Array? Set stores unique values with O(1)
has()lookup. Array allows duplicates with indexed access.When should you use Map instead of Object? When you need non-string keys, frequent add/delete, or insertion-order iteration.
What’s the difference between Set and WeakSet? WeakSet only stores objects and doesn’t prevent garbage collection. Non-iterable, no size.
What is a generator? A function that can pause (
yield) and resume execution. Produces iterators for lazy evaluation.
Challenge: Create a unique function that takes any number of arguments and returns an array with duplicates removed (using Set). Then extend it to work with nested arrays.
FAQ
Try It Yourself
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Collections Playground</title>
<style>
body { font-family: Arial, sans-serif; padding: 2rem; }
pre { background: #f4f4f4; padding: 1rem; border-radius: 5px; }
</style>
</head>
<body>
<h1>Collections Sandbox</h1>
<pre id="output"></pre>
<script>
const out = document.getElementById('output');
let result = '';
// Set — deduplication
const nums = [1, 2, 2, 3, 3, 3, 4];
const unique = [...new Set(nums)];
result += `Original: [${nums}]\n`;
result += `Unique: [${unique}]\n\n`;
// Map — any key type
const map = new Map();
map.set('name', 'Alice');
map.set(42, 'The answer');
map.set(true, 'Boolean key');
result += 'Map entries:\n';
for (const [k, v] of map) {
result += ` ${k} (${typeof k}): ${v}\n`;
}
result += '\n';
// Generator
function* fibonacci(n) {
let a = 0, b = 1;
for (let i = 0; i < n; i++) {
yield a;
[a, b] = [b, a + b];
}
}
result += 'Fibonacci (first 8):\n';
for (const num of fibonacci(8)) {
result += `${num} `;
}
out.textContent = result;
</script>
</body>
</html>What’s Next
Now that you understand collections, learn about async programming and modules:
| Lesson | Description |
|---|---|
| JavaScript Home | Back to the JavaScript hub |
| https://tutorials.dodatech.com/programming-languages/javascript/js-async/ | Async JavaScript — promises and fetch |
| https://tutorials.dodatech.com/programming-languages/javascript/js-modules/ | Modules & Error Handling |
| https://tutorials.dodatech.com/programming-languages/javascript/js-advanced/ | Advanced JavaScript — RegExp, Proxy, performance |
| Node.js Collections | Using collections in Node.js backends |
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
What’s Next
Congratulations on completing this Js Collections tutorial! Here’s where to go from here:
- Practice daily — Consistency is more important than long study sessions
- Build a project — Apply what you learned by building something real
- Explore related topics — Check out other tutorials in the same category
- Join the community — Discuss with other learners and share your progress
Remember: every expert was once a beginner. Keep coding!
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro