API trả ID là chuỗi nhưng giao diện tìm bằng số, nên dữ liệu “có mà không thấy”. Với Map, kiểu và danh tính của khóa là một phần của quy tắc tra cứu. Đổi object chứa dữ liệu sang Map không tự sửa được một contract ID thiếu nhất quán.
Bài viết dùng các ví dụ nhỏ để tách ba việc: xác định khóa, kiểm tra sự tồn tại và quyết định xử lý bản ghi trùng. Ví dụ đã được kiểm tra bằng Node.js local, không truy cập API hay sửa dữ liệu production.
1. Khóa 1 khác khóa '1'
const lookup = new Map();
lookup.set(1, 'numeric');
lookup.set('1', 'text');
console.log(lookup.size); // 2
console.log(lookup.get(1)); // numeric
console.log(lookup.get('1')); // text
MDN Map mô tả kiểu khóa và cách so sánh. Đừng thay get(1) bằng get(String(id)) rải rác để chữa lỗi từng màn hình: hãy thống nhất ID là chuỗi hay số ở biên nhận dữ liệu.
Ví dụ sản phẩm dùng mã '001' khác '1' thì chuyển hết sang Number có thể làm mất ý nghĩa. Nếu ID là chuỗi, quy định cả việc có chấp nhận chuỗi rỗng hay khoảng trắng hay không trước khi đưa vào cấu trúc tra cứu.
2. Object key được nhận diện bằng tham chiếu
const key = { id: 1 };
const cache = new Map([[key, 'ready']]);
console.log(cache.get(key)); // ready
console.log(cache.get({ id: 1 })); // undefined
Hai object có cùng trường id không phải cùng một object. Nếu cần tra cứu thực thể theo ID nghiệp vụ, thường nên dùng ID đã chuẩn hóa làm khóa thay vì tạo object mới ở mỗi lần gọi.
Đặc tả ECMAScript về Map định nghĩa hành vi khóa và cập nhật entry. Khi dùng object key cho cache theo instance, hãy kiểm tra thêm vòng đời cache và thời điểm xóa entry; ví dụ này không triển khai eviction hay giới hạn dung lượng.
3. get() không thay thế has()
const states = new Map([['task-1', undefined]]);
console.log(states.get('task-1')); // undefined
console.log(states.get('task-2')); // undefined
console.log(states.has('task-1')); // true
console.log(states.has('task-2')); // false
Nếu undefined là một giá trị hợp lệ trong bộ nhớ, get() không phân biệt được “có khóa với giá trị undefined” và “không có khóa”. Dùng has() để hỏi về sự tồn tại, theo tài liệu Map.prototype.has().
Tương tự, kiểm tra if (map.get(key)) có thể bỏ qua false, 0 hoặc chuỗi rỗng. Trong thiết kế trạng thái, nên đặt tên rõ cho các trạng thái như chưa tải, đang tải, không tìm thấy và đã có dữ liệu, thay vì buộc mọi ý nghĩa vào một giá trị falsy.
4. Xác định chính sách ID trùng trước khi lập index
Hàm minh họa dưới đây chỉ chấp nhận mảng các record có ID chuỗi không rỗng, không có khoảng trắng đầu/cuối, đồng thời từ chối ID trùng. Nó giữ tham chiếu record gốc, không clone dữ liệu:
function indexRecords(rows) {
if (!Array.isArray(rows)) throw new TypeError('Expected an array');
const index = new Map();
for (const row of rows) {
if (row === null || typeof row !== 'object' || Array.isArray(row)
|| !Object.hasOwn(row, 'id')
|| typeof row.id !== 'string'
|| row.id.length === 0 || row.id.trim() !== row.id) {
throw new TypeError('Expected a record with a canonical string id');
}
if (index.has(row.id)) throw new Error('Duplicate id');
index.set(row.id, row);
}
return index;
}
Từ chối trùng là một lựa chọn contract. Với nguồn dữ liệu khác, sản phẩm có thể chọn record đầu, record cuối hoặc gộp dữ liệu. Hãy viết rõ quy tắc thay vì vô tình dựa vào lần set cuối cùng để che bản ghi trước.
Phạm vi hàm là object dữ liệu thông thường. Nó không phải schema validator đầy đủ cho mọi field, không xử lý object có getter/Proxy không tin cậy và không kiểm tra quyền truy cập. Backend vẫn phải thực thi contract riêng.
5. Chuyển sang JSON có chủ đích
const labels = new Map([['a', 'Alpha'], ['b', 'Beta']]);
console.log(JSON.stringify(labels)); // {}
const json = JSON.stringify([...labels]);
const restored = new Map(JSON.parse(json));
console.log(restored.get('a')); // Alpha
Map thông thường không có cơ chế JSON serialization trực tiếp cho các entry; xem MDN JSON.stringify(). Mảng cặp khóa/giá trị trong ví dụ là một format được chọn rõ ràng.
Ví dụ round-trip chỉ dùng khóa và giá trị chuỗi. Nó không chứng minh mọi Map đều khôi phục nguyên vẹn: undefined, object identity và các kiểu không có biểu diễn JSON tương ứng cần chính sách riêng. Dữ liệu nhận từ bên ngoài còn phải kiểm tra cấu trúc từng cặp, kiểu khóa và ID trùng trước khi dựng Map.
6. Checklist khi review
- Kiểu ID thống nhất giữa API, form và code tra cứu.
- Không dùng map[key] thay cho set/get của Map.
- Object key có thực sự cần danh tính instance hay chỉ cần ID?
- Dùng has() khi cần phân biệt thiếu khóa với giá trị undefined.
- Có quy tắc rõ cho bản ghi trùng và record bị sửa sau khi lập index.
- Format lưu trữ/JSON đã được xác định và validation ở biên dữ liệu.
- Nếu Map sống lâu, có giới hạn kích thước hoặc chính sách xóa phù hợp.
Các ví dụ và hàm index đã qua kiểm tra cho khóa khác kiểu, object identity, giá trị undefined, ID sai định dạng, ID trùng và JSON với cặp chuỗi. Kiểm tra này xác minh hành vi minh họa, không phải benchmark Map so với object.
Map phát huy giá trị khi quy tắc khóa được thiết kế rõ. Thống nhất ID và chính sách trùng trước sẽ giúp việc tra cứu dễ dự đoán hơn việc chỉ đổi sang một cấu trúc dữ liệu mới.




Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.