Map, Set, WeakMap & WeakSet
debt(d5/e3/b3/t5)
Closest to 'specialist tool catches it' (d5). ESLint and TypeScript can detect some patterns (Object used as map, Array.indexOf for membership), but detection is not automatic or comprehensive. The code_pattern hints indicate these are detectable via linting rules, but require explicit rule configuration and don't catch all misuses (e.g., subtle prototype pollution edge cases only emerge in code review or runtime testing).
Closest to 'simple parameterised fix' (e3). The quick_fix states the solution is straightforward: replace Object with Map for non-string keys, or array with Set for membership checks. These are typically single-file, single-component refactors within a data structure usage, not cross-cutting changes. No architectural rework required.
Closest to 'localised tax' (b3). Map/Set choices are typically confined to the component or module where they're used. While applies_to includes both web and cli contexts, this choice doesn't impose reach across the system or gravitational pull on future architecture. The decision affects only the data structure layer in isolated components, not global patterns or shared abstractions.
Closest to 'notable trap' (t5). The misconception field directly identifies the trap: developers believe plain objects are always fine as dictionaries, unaware of prototype property surprises (constructor, toString) and that object keys coerce to strings. This is a documented gotcha that most JavaScript developers eventually learn through experience or code review. Common mistakes confirm iteration gotchas (for...in vs for...of) add cognitive friction beyond the initial data structure choice.
Also Known As
TL;DR
Explanation
Map is like an object but allows any type as key, maintains insertion order, and has built-in size. Set stores unique values of any type. WeakMap and WeakSet hold weak references — keys (WeakMap) or values (WeakSet) are garbage collected when no other references exist. Map vs object: Maps are better for frequent add/delete operations and non-string keys. Set vs array: Set membership is O(1); array includes() is O(n). WeakMap is ideal for private data and caches keyed by object instances.
Common Misconception
Why It Matters
Common Mistakes
- Using an object instead of Map for a dictionary with non-string keys — object keys are always coerced to strings.
- Iterating a Map with for...in — use for...of or Map.forEach(); for...in is for object prototype chains.
- Not using Set for deduplication — [...new Set(array)] is the cleanest deduplication pattern.
- Using Map where a plain object suffices for static, known string keys — Map has overhead for simple static configs.
Code Examples
// Array for deduplication — O(n²):
const unique = arr.filter((v, i) => arr.indexOf(v) === i); // indexOf is O(n)
// Object as dictionary with non-string keys:
const map = {};
map[objectKey] = value; // key coerced to '[object Object]' — all map to same slot
// Set for O(n) deduplication:
const unique = [...new Set(arr)];
// Map for any-type keys:
const cache = new Map();
cache.set(objectInstance, computedValue);
cache.get(objectInstance); // Uses object identity, not string coercion
// WeakMap for private data (GC-safe):
const _private = new WeakMap();
class User {
constructor(name) { _private.set(this, { name }); }
getName() { return _private.get(this).name; }
}