Object
Chỉ dùng string/symbol làm key — object bị ép thành "[object Object]"
Map là “cuốn sổ ghi chép” gồm các cặp khóa → giá trị. Điểm khác biệt quan trọng so với Object: khóa có thể là bất kỳ thứ gì — object, mảng, hàm — và Map giữ đúng thứ tự chèn.
Object cho xong?Object
Chỉ dùng string/symbol làm key — object bị ép thành "[object Object]"
Map
Giữ nguyên khóa gốc (so sánh theo tham chiếu), có size, dễ lặp, tra cứu O(1)
const m = new Map();m.set(key, value); // thêm/cập nhậtm.get(key); // lấy ra (không có → undefined)m.has(key); // kiểm tra có key khôngm.delete(key); // xóa theo keym.clear(); // xóa tất cảm.size; // số cặp khóa-giá trịconst u1 = { id: 1, name: "An" };const u2 = { id: 2, name: "Bình" };
const roles = new Map();roles.set(u1, "admin");roles.set(u2, "viewer");
console.log(roles.get(u1)); // "admin"console.log(roles.has(u2)); // trueconsole.log(roles.size); // 2Key là object
Gắn metadata cho DOM node, user object, v.v.
Thứ tự chèn
Cần bảo toàn thứ tự khi lặp (for...of, map.entries())
API rõ ràng
set/get/has + map.size — đo kích thước nhanh gọn
const s = "banana";const freq = new Map();for (const ch of s) freq.set(ch, (freq.get(ch) ?? 0) + 1);// [...freq] → [ ['b',1], ['a',3], ['n',2] ]Hãy tưởng tượng bạn dán một “note” vào chính object để lưu dữ liệu phụ. Khi object biến mất (không còn biến nào trỏ tới), “note” cũng tự rơi — bạn không phải dọn rác. Đó là WeakMap.
for...of, keys(), values(), entries()sizefor...of, không sizeset/get/has/deleteconst wm = new WeakMap();wm.set(obj, value);wm.get(obj); // → value | undefinedwm.has(obj); // → booleanwm.delete(obj); // → booleanPrivate State
Gắn metadata/private state cho instance mà không lo rò rỉ bộ nhớ
Cache
Cache theo object — kết quả tự hết hạn khi object gốc bị GC
Trạng thái tạm
Lưu trạng thái gắn với vòng đời object (đã xử lý, cấu hình tạm, v.v.)
const _priv = new WeakMap();
class User { constructor(name) { this.name = name; _priv.set(this, { token: Math.random().toString(36).slice(2) }); } getToken() { return _priv.get(this).token; }}
let u = new User("An");console.log(u.getToken());// Khi u = null → entry trong WeakMap tự biến mấtconst measureCache = new WeakMap();
function measure(el) { if (measureCache.has(el)) return measureCache.get(el); const rect = el.getBoundingClientRect(); const info = { w: rect.width, h: rect.height }; measureCache.set(el, info); return info;}// Khi el bị remove → cache entry biến mất cùng elSet là tập hợp không trùng lặp, có thứ tự chèn. Thao tác tra cứu/thêm/xóa trung bình O(1).
const s = new Set();s.add(value); // thêm phần tửs.has(value); // kiểm tra tồn tạis.delete(value); // xóa phần tửs.clear(); // xóa tất cảs.size; // số phần tửconst uniq = new Set([1, 2, 2, 3, 3]);console.log([...uniq]); // [1, 2, 3]
uniq.add(4);console.log(uniq.has(2)); // trueconsole.log(uniq.size); // 4const a = new Set([1, 2, 3]);const b = new Set([2, 3, 4]);
// Giao (intersection)const intersection = new Set([...a].filter(x => b.has(x))); // {2, 3}
// Hợp (union)const union = new Set([...a, ...b]); // {1, 2, 3, 4}
// Hiệu (difference)const diff = new Set([...a].filter(x => !b.has(x))); // {1}WeakSet là tập hợp yếu của object (không nhận primitive). Không lặp, không size; phần tử bị GC thu gom khi không còn tham chiếu khác.
const ws = new WeakSet();ws.add(obj); // thêm objectws.has(obj); // kiểm tra tồn tạiws.delete(obj); // xóa objectconst visited = new WeakSet();
function traverse(node) { if (visited.has(node)) return; // đã duyệt rồi → bỏ qua visited.add(node); // ... duyệt con}| Đặc điểm | Map | WeakMap | Set | WeakSet |
|---|---|---|---|---|
| Key/Phần tử | Bất kỳ | Object only | Bất kỳ | Object only |
| GC thu gom? | ❌ | ✅ | ❌ | ✅ |
| Có thể lặp? | ✅ | ❌ | ✅ | ❌ |
Có size? | ✅ | ❌ | ✅ | ❌ |
| JSON serialize? | Cần chuyển đổi | ❌ | Cần chuyển đổi | ❌ |