Một danh sách có Mục 1, Mục 2 và Mục 10 lại hiển thị theo thứ tự 1, 10, 2. Đó có thể là kết quả hợp lệ của cách so chuỗi đang dùng, nhưng không khớp mong đợi đọc số trong tên. Khi tên có tiếng Việt và chữ số, cần chọn quy tắc sắp thứ tự rõ ràng thay vì tự cắt vài ký tự rồi ép thành số.
Bài đối chiếu MDN ngày 10/11/2026, chạy trên Node.js 24.18.1 với ICU 78.3. Tiêu chí so sánh gồm nghĩa của thứ tự, cấu hình locale, cách xử lý tên tương đương và phạm vi triển khai. Không có benchmark hoặc kết luận tốc độ trên browser, Hermes hay thiết bị.
So kết quả trước khi đổi code sản phẩm
const names = ['Mục 10', 'Mục 2', 'Mục 1'];
const collator = new Intl.Collator('vi', {numeric: true});
console.log(JSON.stringify([...names].sort()));
console.log(JSON.stringify([...names].sort(collator.compare)));
console.log(collator.resolvedOptions().locale);
Trong môi trường kiểm tra, hai danh sách lần lượt là Mục 1, Mục 10, Mục 2 và Mục 1, Mục 2, Mục 10; locale được phân giải là vi. Hai lời gọi đều nhận một array sao chép để không làm đổi thứ tự array names trong fixture.
Intl.Collator constructor mô tả tùy chọn numeric cho việc so các đoạn chữ số theo giá trị số. Nó không chuyển toàn bộ tên thành một Number và không thay thế một parser định dạng dữ liệu nghiệp vụ.
Một cấu hình dùng lại cho nhiều phép so
Collator là một đối tượng giữ lựa chọn locale và options cho việc so sánh. Tạo nó tại phạm vi phù hợp rồi dùng compare giúp người đọc thấy quy tắc của danh sách nằm ở đâu. Không cần xây một bộ quy tắc cắt hậu tố số nếu yêu cầu của màn hình chính là thứ tự collation có numeric như ví dụ.
Theo compare, điều có ý nghĩa là dấu âm, dấu dương hoặc 0. Đừng viết kiểm tra buộc mọi cặp phải trả đúng -1 hoặc 1. Chỉ kiểm tra dấu hoặc thứ tự cuối cùng mà ứng dụng yêu cầu.
Khi tên khác chuỗi nhưng được so là ngang nhau
console.log(collator.compare('Mục 02', 'Mục 2'));
const records = [
{id: 20, name: 'Mục 02'},
{id: 10, name: 'Mục 2'},
{id: 30, name: 'Mục 10'},
];
const ordered = [...records].sort((a, b) =>
collator.compare(a.name, b.name) || a.id - b.id,
);
console.log(JSON.stringify(ordered.map(record => record.id)));
Fixture cho kết quả so bằng 0 và danh sách ID 10, 20, 30. Khóa phụ bằng ID giúp ví dụ quy định thứ tự cho hai tên được collator xem tương đương. ID ở đây là các số nguyên phân biệt đã biết; đoạn code không kiểm tra schema bản ghi hoặc giải quyết ID bị trùng.
Đừng dùng kết quả compare bằng 0 để kết luận hai bản ghi là cùng một thực thể. Quy tắc sắp tên và quy tắc định danh có mục đích khác nhau. Nếu tên dùng để tìm kiếm, xác định chính sách tìm kiếm riêng thay vì tự động nhận mọi option của phép sắp xếp.
Chọn cấu hình theo yêu cầu thật
Intl.Collator còn có các lựa chọn liên quan đến cách phân biệt chữ hoa và dấu. Bài chỉ kiểm thử numeric với các tên đã nêu, không chứng minh thứ tự của toàn bộ tiếng Việt hoặc mọi tổ hợp options. Khi sản phẩm có yêu cầu thứ tự tên người, hãy lấy ví dụ đại diện từ chính yêu cầu ấy.
Kiểm tra resolvedOptions và hỗ trợ locale trong runtime mục tiêu, nhất là khi mã chạy cả server và mobile. Một kết quả Node có ICU đầy đủ không bảo đảm một runtime khác chọn cùng dữ liệu locale hoặc cho cùng mọi thứ tự. Nếu cần thứ tự nhất quán giữa server phân trang và client hiển thị, thỏa thuận nơi chịu trách nhiệm sắp xếp và khóa phụ từ đầu.
Cách đánh giá trước khi áp dụng
Giữ bộ ca gồm tên có 1/2/10, tên trùng, tên có số 0 đầu và các chuỗi tiếng Việt mà người dùng thường gặp. Kiểm tra array gốc không đổi nếu caller cần giữ nó. Rà riêng bản ghi thiếu name hoặc sai kiểu thay vì để ép kiểu làm mất dấu dữ liệu không hợp lệ.
Về chi phí áp dụng, ví dụ dùng API tích hợp sẵn và không thêm package. Việc lựa chọn vẫn cần dựa trên semantics và khả năng runtime; bài không có bằng chứng tiết kiệm thời gian xử lý. Hãy chọn collator vì nó thể hiện đúng quy tắc đọc danh sách, rồi mới đo nếu quy mô dữ liệu khiến hiệu năng trở thành vấn đề thực tế.

