JSON, Set, Map & WeakMap
Object keys sirf strings hote hain — kya kabhi socha? Map koi bhi key type allow karta hai, WeakMap GC ka bestie hai.
JSON (JavaScript Object Notation) is the universal data exchange format. Every API, every config file, every database speaks JSON. But it has strict rules about what it supports.
const data = { name: 'Sai', active: true, score: 99.5 };
// Stringify (JS → JSON string)
const jsonStr = JSON.stringify(data);
console.log(jsonStr); // '{"name":"Sai","active":true,"score":99.5}'
// Parse (JSON string → JS)
const parsed = JSON.parse(jsonStr);
// Pretty print with spaces
console.log(JSON.stringify(data, null, 2));
// The Date problem
const withDate = { created: new Date() };
const dateJson = JSON.stringify(withDate);
console.log(dateJson); // {"created":"2024-01-01T12:00:00.000Z"} (String!)
const back = JSON.parse(dateJson);
console.log(typeof back.created); // 'string' — Date is no longer a Date!
// Reviver to fix Dates
const fixed = JSON.parse(dateJson, (key, value) => {
if (key === 'created') return new Date(value);
return value;
});
console.log(fixed.created instanceof Date); // true ✅
The replacer function/array in JSON.stringify lets you filter or transform values before serialization. The reviver function in JSON.parse lets you transform values during deserialization — like resurrecting Date objects from strings.
Set is a collection of unique values. It automatically removes duplicates using the SameValueZero algorithm, which is slightly different from ===.
// Create and add
const uniqueIds = new Set();
uniqueIds.add(1);
uniqueIds.add(2);
uniqueIds.add(2); // Ignored!
console.log(uniqueIds.size); // 2
// Initialize from array (remove duplicates)
const nums = [1, 2, 2, 3, 3, 3];
const unique = [...new Set(nums)]; // [1, 2, 3]
// SameValueZero: NaN equals NaN
const special = new Set();
special.add(NaN);
special.add(NaN); // Ignored!
console.log(special.has(NaN)); // true ✅ (unlike ===)
// Object reference trap
const objSet = new Set();
objSet.add({ id: 1 }); // Object A
objSet.add({ id: 1 }); // Object B (different reference!)
console.log(objSet.size); // 2 — they are different objects!
// To make it 1, use the SAME reference
const objA = { id: 1 };
objSet.add(objA);
objSet.add(objA); // Ignored
console.log(objSet.size); // Still 3 (A, B, objA)
.add(value), .has(value), .delete(value), .clear(), .size. Set is iterable in insertion order. The most common use case is removing duplicates from an array: [...new Set(arr)]. Remember: objects are compared by reference, not by value — two objects with identical properties are still different entries in a Set.Map is a key-value collection where keys can be any type — not just strings like plain objects. This is the fix for the infamous [object Object] key problem.
// The Object Key Problem
const obj = {};
const key1 = { id: 1 };
const key2 = { id: 2 };
obj[key1] = 'value 1';
obj[key2] = 'value 2'; // Overwrites value 1!
// Both keys became "[object Object]"
console.log(obj); // { "[object Object]": "value 2" }
// Map solves this
const map = new Map();
map.set(key1, 'value 1');
map.set(key2, 'value 2');
console.log(map.get(key1)); // 'value 1' ✅
console.log(map.size); // 2
// Map accepts any key type
map.set(1, 'number key');
map.set(true, 'boolean key');
map.set(null, 'null key');
// Iteration (insertion order)
for (const [key, val] of map) {
console.log(key, val);
}
// Convert Map to Object and vice versa
const objFromMap = Object.fromEntries(map);
const mapFromObj = new Map(Object.entries({ a: 1, b: 2 }));
WeakMap and WeakSet are like Map and Set, but with one critical difference: keys (for WeakMap) or values (for WeakSet) are held weakly. This means if the only reference to the key object is inside the WeakMap, the garbage collector can reclaim it.
// WeakMap for private data
const privateData = new WeakMap();
class User {
constructor(name) {
this.name = name;
privateData.set(this, { loginCount: 0 }); // Private!
}
login() {
const data = privateData.get(this);
data.loginCount++;
console.log(this.name + ' logged in ' + data.loginCount + ' times');
}
}
const sai = new User('Sai');
sai.login(); // Sai logged in 1 times
// sai.privateData -> undefined (truly private)
// When 'sai' is set to null, the WeakMap entry is garbage collected
// No memory leak!
// WeakSet for tracking processed items
const processed = new WeakSet();
function processItem(item) {
if (processed.has(item)) {
console.log('Already processed!');
return;
}
// ... process item ...
processed.add(item);
}
.keys(), .values(), .forEach(), or .size. Why? Because entries can disappear at any time when GC runs. This makes iteration non-deterministic, so the spec disallows it. Use cases: private data for class instances, caching computed values, DOM node metadata without causing memory leaks.JavaScript has three different equality algorithms, and they behave differently with edge cases like NaN and -0. Understanding which one Map/Set uses is crucial.
// Strict Equality (===)
console.log(NaN === NaN); // false ❌
console.log(-0 === +0); // true
// Object.is
console.log(Object.is(NaN, NaN)); // true ✅
console.log(Object.is(-0, +0)); // false (they are different!)
// SameValueZero (Map/Set behavior)
// Simulated:
function sameValueZero(x, y) {
if (typeof x === 'number' && typeof y === 'number') {
// x is NaN AND y is NaN
if (x !== x && y !== y) return true; // NaN check
// +0 and -0 are treated as equal
if (Object.is(x, y)) return true;
return x === y;
}
return Object.is(x, y);
}
// Why it matters for Map
const map = new Map();
map.set(NaN, 'Not a Number');
console.log(map.get(NaN)); // 'Not a Number' ✅ (NaN works as a key!)
map.set(-0, 'Negative Zero');
console.log(map.get(+0)); // 'Negative Zero' (-0 and +0 are same key)
• Map and Set using SameValueZero is a huge quality-of-life improvement. In plain objects, using
NaN as a key doesn't work as expected because obj[NaN] converts to obj["NaN"], which is just a string. In Map, NaN is truly recognized as NaN.• The ONLY difference between SameValueZero and Object.is is the
-0/+0 behavior.Lo kar liya — Key Points:
- ✅ JSON.stringify converts Dates to strings and drops undefined/functions; use a reviver to restore types
- ✅ Set stores unique values using SameValueZero (NaN equals NaN); objects are unique by reference, not value
- ✅ Map allows ANY key type (objects, functions, primitives) and maintains insertion order
- ✅ Plain objects coerce keys to strings (
[object Object]); Maps do not - ✅ WeakMap/WeakSet hold keys weakly — if the key object is garbage collected, the entry disappears
- ✅ SameValueZero (Map/Set) treats
NaN === NaNas true and-0 === +0as true; Object.is treats -0 and +0 as different
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login