Bỏ qua để đến nội dung

Keyed Collections — Map & Set

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

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ật
m.get(key); // lấy ra (không có → undefined)
m.has(key); // kiểm tra có key không
m.delete(key); // xóa theo key
m.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)); // true
console.log(roles.size); // 2

Key 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.

  • Key có thể là bất kỳ giá trị nào
  • Không yếu — giữ tham chiếu mạnh đến key
  • Có thể lặpfor...of, keys(), values(), entries()
  • size

const wm = new WeakMap();
wm.set(obj, value);
wm.get(obj); // → value | undefined
wm.has(obj); // → boolean
wm.delete(obj); // → boolean

Private 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ất
const 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 el

Set 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ại
s.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)); // true
console.log(uniq.size); // 4
const 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 object
ws.has(obj); // kiểm tra tồn tại
ws.delete(obj); // xóa object
const 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ểmMapWeakMapSetWeakSet
Key/Phần tửBất kỳObject onlyBất kỳObject only
GC thu gom?
Có thể lặp?
size?
JSON serialize?Cần chuyển đổiCần chuyển đổi