060: JavaScript Data Structures: Map, Set, Weak Collections, JSON, and Typed Arrays
Outcomes
By the end of this lesson, you can:
- choose between
Object,Map, andSet; - use
WeakMapandWeakSetappropriately; - explain why weak collections are not enumerable;
- serialize and parse JSON safely;
- identify JSON's data-model limitations;
- explain the role of
ArrayBufferand typed arrays.
Map: Keyed Data with Any Key Type
Objects are excellent records. Map is excellent when the data is fundamentally a dynamic key/value collection.
const stockByProduct = new Map();
stockByProduct.set("tea", 10);
stockByProduct.set("coffee", 5);
console.log(stockByProduct.get("tea"));
console.log(stockByProduct.has("coffee"));
console.log(stockByProduct.size);
Keys can be objects:
const user = { id: 1 };
const preferences = new Map();
preferences.set(user, { theme: "dark" });
console.log(preferences.get(user));
Iterating a Map
for (const [key, value] of stockByProduct) {
console.log(key, value);
}
Maps preserve insertion order.
Set: Unique Values
const selectedTags = new Set();
selectedTags.add("featured");
selectedTags.add("sale");
selectedTags.add("sale");
console.log(selectedTags.size); // 2
A common deduplication pattern:
const unique = [...new Set(["a", "b", "a"])];
Object versus Map
Use an object when you are modeling a structured entity:
const customer = {
id: 1,
name: "Maya",
active: true,
};
Use a Map when keys are dynamic collection data:
const countsBySku = new Map();
Do not replace every object with a Map merely because Map has convenient methods.
WeakMap
WeakMap keys must be objects, and the collection does not keep those key objects alive by itself.
const metadata = new WeakMap();
let button = document.querySelector("button");
metadata.set(button, {
clicks: 0,
});
console.log(metadata.get(button));
If nothing else references the button object, garbage collection can reclaim it; the WeakMap does not provide enumeration that would expose its lifetime.
Typical uses include private metadata and caches tied to object lifetime.
WeakSet
WeakSet stores object membership weakly.
const processed = new WeakSet();
function process(order) {
if (processed.has(order)) {
return;
}
processed.add(order);
console.log("processing", order.id);
}
Structured Data with JSON
JSON supports a smaller data model than JavaScript.
const payload = {
id: 101,
name: "Tea",
active: true,
tags: ["hot", "drink"],
metadata: null,
};
const json = JSON.stringify(payload);
const parsed = JSON.parse(json);
JSON Limitations
JSON does not directly preserve:
undefined;- functions;
- Symbols;
- BigInts;
MapandSet;Dateidentity;- prototypes;
- circular references.
JSON.stringify({
value: undefined,
fn() {},
}); // "{}"
BigInt throws:
// JSON.stringify({ id: 1n }); // TypeError
JSON Reviver and Replacer
const json = JSON.stringify(
{ total: 100, secret: "remove-me" },
(key, value) => key === "secret" ? undefined : value
);
Reviver:
const data = JSON.parse(
'{"createdAt":"2026-08-27T10:00:00.000Z"}',
(key, value) => {
if (key === "createdAt") {
return new Date(value);
}
return value;
}
);
Use these features carefully; explicit normalization functions are often easier to maintain.
Typed Arrays
Ordinary arrays can store mixed JavaScript values. Typed arrays provide numeric views over binary memory.
const bytes = new Uint8Array([65, 66, 67]);
console.log(bytes[0]); // 65
Underlying buffer:
const buffer = new ArrayBuffer(4);
const view = new Uint8Array(buffer);
view[0] = 255;
console.log(view);
Typed arrays matter for:
- files and binary protocols;
- graphics and audio;
- WebAssembly;
- network binary data;
- performance-sensitive numeric work.
Do not use them for ordinary business arrays without a reason.
Worked Example: Inventory Index
function buildInventoryIndex(products) {
const bySku = new Map();
const categories = new Set();
for (const product of products) {
bySku.set(product.sku, product);
categories.add(product.category);
}
return { bySku, categories };
}
const index = buildInventoryIndex([
{ sku: "BIR-1", category: "food", name: "Biryani" },
{ sku: "TEA-1", category: "drink", name: "Tea" },
{ sku: "TEA-2", category: "drink", name: "Black Tea" },
]);
console.log(index.bySku.get("TEA-1"));
console.log([...index.categories]);
Failure Example: Stringifying a Map
const map = new Map([["tea", 10]]);
console.log(JSON.stringify(map)); // "{}"
Normalize it explicitly:
const json = JSON.stringify(Object.fromEntries(map));
And restore if needed:
const restored = new Map(
Object.entries(JSON.parse(json))
);
Advanced Notes: Complexity and Collection Semantics
Do not choose a collection only from theoretical complexity, but understand the common operations.
If you repeatedly search an array by ID:
function findById(items, id) {
return items.find((item) => item.id === id);
}
each lookup scans until a match is found.
An index trades construction/update work and memory for direct lookup:
const byId = new Map(
items.map((item) => [item.id, item])
);
console.log(byId.get("P-100"));
That can be valuable when lookups are frequent and the collection changes in controlled ways.
Set operations
Modern runtimes increasingly provide Set composition methods, but compatibility can vary. A portable intersection can be written as:
function intersection(first, second) {
return new Set(
[...first].filter((value) => second.has(value))
);
}
Binary data and DataView
DataView can read different numeric types and byte orders from an ArrayBuffer.
const buffer = new ArrayBuffer(4);
const view = new DataView(buffer);
view.setUint16(0, 500, false);
console.log(view.getUint16(0, false));
You do not need binary APIs for most CRUD applications, but you should recognize them when working with files, media, hardware protocols, WebSockets, or WebAssembly.
Best Practices
- Use Objects for records and Maps for dynamic keyed collections.
- Use Sets for uniqueness/membership.
- Use weak collections only when object lifetime semantics are part of the problem.
- Treat JSON as a transport/storage representation, not a clone of the JavaScript object model.
- Validate parsed JSON before trusting its shape.
- Use typed arrays only when binary/numeric memory is actually required.
Exercises
Core
Build a Set of unique category names.
Practice
Build a Map keyed by product ID and implement findProduct(id).
Professional Extension
Create serializer/deserializer helpers that convert a Map of inventory quantities to JSON and restore it.
Recap
JavaScript has multiple data structures because different data has different semantics. Choosing the right structure makes intent and performance characteristics clearer.
