UTF-16
Bảng mã Unicode sử dụng đơn vị mã 16-bit. Được sử dụng nội bộ bởi JavaScript, Java và Windows.
UTF-16 là bảng mã Unicode biểu diễn ký tự trong đơn vị 16-bit (2 byte). Các ký tự trong Mặt phẳng đa ngôn ngữ cơ bản (BMP, U+0000-U+FFFF) sử dụng 2 byte, trong khi các ký tự ngoài BMP sử dụng cặp thay thế yêu cầu 4 byte. Nó được áp dụng làm biểu diễn chuỗi nội bộ trong nhiều môi trường lập trình bao gồm JavaScript, Java, C# và Windows API.
Vì chuỗi JavaScript nội bộ là UTF-16, String.length trả về số đơn vị mã UTF-16. Ví dụ, emoji "😀" (U+1F600) được biểu diễn dưới dạng cặp thay thế, vì vậy length của nó là 2, không phải 1. charAt() và charCodeAt() cũng hoạt động ở cấp đơn vị mã, có thể chỉ lấy được một nửa cặp thay thế. Từ ES2015, codePointAt() và vòng lặp for...of cho phép xử lý ở cấp code point.
UTF-16 có cân nhắc về thứ tự byte (endianness). UTF-16BE (big-endian) và UTF-16LE (little-endian) tồn tại, với BOM (Byte Order Mark, U+FEFF) ở đầu tệp để xác định thứ tự byte. Windows Notepad lưu "Unicode" dưới dạng UTF-16LE có BOM. Mặc dù chuẩn hóa UTF-8 trên web đã giảm gặp phải vấn đề thứ tự byte UTF-16, vẫn cần chú ý khi giao tiếp với môi trường Windows hoặc hệ thống cũ.
So với UTF-8, ký tự ASCII dùng 1 byte trong UTF-8 so với 2 byte trong UTF-16, khiến UTF-8 hiệu quả hơn về kích thước cho văn bản tiếng Anh. Ngược lại, ký tự CJK sử dụng 3 byte trong UTF-8 so với 2 byte trong UTF-16, khiến UTF-16 gọn hơn cho văn bản tiếng Nhật và tiếng Trung. Tuy nhiên, với tiêu chuẩn web thống nhất trên UTF-8, thực hành phổ biến là sử dụng UTF-8 cho lưu trữ tệp và truyền thông trong khi sử dụng UTF-16 cho xử lý chuỗi nội bộ.
Đối với đếm ký tự, xử lý cặp thay thế là thách thức lớn nhất trong các ngôn ngữ dựa trên UTF-16 (JavaScript, Java). Sử dụng String.length trực tiếp đếm thừa emoji và một số ký tự CJK. Đếm chính xác yêu cầu [...str].length (cú pháp spread) hoặc Array.from(str).length cho số code point, hoặc Intl.Segmenter cho số cụm grapheme.