Gọi value.toString(16) không tự bảo đảm đầu ra là hai chữ số hex đại diện một byte. Số âm vẫn có dấu, số lớn có thể dài hơn hai ký tự và phần thập phân vẫn có thể xuất hiện. Muốn trao đổi giá trị byte qua chuỗi hex, cần định nghĩa miền số và định dạng đầu vào rõ ràng.
1. Đổi cơ số chỉ tạo biểu diễn của số
console.log((15).toString(16)); // f
console.log((256).toString(16)); // 100
console.log((-1).toString(16)); // -1
console.log((1.5).toString(16)); // 1.8
Number.toString nhận radix để chọn cơ số biểu diễn. Giá trị -1 không tự biến thành ff theo cách biểu diễn byte bù hai. Kết quả cũng không tự có tiền tố 0x hoặc độ rộng cố định.
Đừng xử lý vượt biên bằng cách lấy hai ký tự cuối nếu sản phẩm chưa quy định việc cắt dữ liệu. Chẳng hạn 256 không phải byte không dấu hợp lệ; đổi nó thành 00 sẽ che việc mất thông tin. Tương tự, việc tự làm tròn 1.5 cũng cần một chính sách riêng.
2. Mã hóa đúng miền byte không dấu
function toHexByte(value) {
if (!Number.isInteger(value)) {
throw new TypeError('byte must be an integer number');
}
if (value < 0 || value > 255) {
throw new RangeError('byte must be between 0 and 255');
}
return value.toString(16).padStart(2, '0');
}
console.log(toHexByte(0)); // 00
console.log(toHexByte(15)); // 0f
console.log(toHexByte(255)); // ff
Helper nhận number nguyên trong khoảng 0–255 rồi trả đúng hai ký tự hex viết thường, không có tiền tố. Number.isInteger không tự chấp nhận chuỗi số. Kiểm tra miền trước khi padStart giúp độ rộng hai ký tự là hệ quả của contract thay vì một kỳ vọng chưa kiểm chứng.
Giá trị -0 đi qua kiểm tra như 0 và được biểu diễn thành 00; contract này không giữ dấu của số 0. Nếu đầu vào là byte có dấu, cần quy định phép chuyển sang miền không dấu trước, thay vì bỏ kiểm tra hoặc áp dụng toán tử bit để che lỗi đầu vào.
3. Giải mã cả chuỗi, không chỉ phần đầu hợp lệ
function fromHexByte(text) {
if (typeof text !== 'string') {
throw new TypeError('hex byte must be a string');
}
if (!/^[0-9A-Fa-f]{2}$/.test(text)) {
throw new RangeError('expected exactly two hexadecimal digits');
}
return Number.parseInt(text, 16);
}
console.log(fromHexByte('00')); // 0
console.log(fromHexByte('0F')); // 15
console.log(fromHexByte('ff')); // 255
Regex yêu cầu đúng hai chữ số hex ASCII. Chuỗi một ký tự, tiền tố 0x, khoảng trắng và dữ liệu nối đuôi bị từ chối. parseInt có thể dừng tại ký tự không hợp lệ rồi trả phần số đã đọc, nên bản thân nó chưa thay thế kiểm tra toàn chuỗi.
Decoder nhận cả chữ hoa và chữ thường; encoder luôn trả chữ thường. Vì thế fromHexByte(toHexByte(n)) giữ giá trị của mọi byte, nhưng toHexByte(fromHexByte('0F')) cho '0f'. Đây là chuẩn hóa định dạng có chủ đích, không phải khôi phục nguyên văn mọi chuỗi đầu vào.
4. Một byte chưa định nghĩa cả giao thức
Hai helper không quyết định thứ tự byte của số nhiều byte, cách mã hóa văn bản, dấu phân cách giữa các byte hay cấu trúc gói tin. Những điều đó phải nằm trong contract của bên gửi và bên nhận. Đừng dùng kết quả một byte để suy ra toàn bộ định dạng file hoặc payload đã đúng.
Ví dụ cũng không kiểm tra ý nghĩa nghiệp vụ của byte. Một giá trị nằm trong 0–255 có thể vẫn không phải mã trạng thái được hỗ trợ hoặc giá trị cấu hình hợp lệ. Kiểm tra định dạng và kiểm tra nghiệp vụ là hai bước cần được phân biệt khi báo lỗi.
5. Checklist trước khi chuyển số thành hex
- Đầu vào là một byte không dấu hay kiểu số khác?
- Miền giá trị, quy tắc số âm và phần thập phân đã rõ chưa?
- Có yêu cầu hai ký tự, tiền tố hoặc chữ hoa/thường cụ thể?
- Decoder có kiểm tra toàn chuỗi trước khi parse?
- Test đã kiểm tra đủ giá trị biên và chiều round-trip cần giữ?
Sáu khối mã Việt–Anh đã chạy bằng Node.js. Kiểm tra bổ sung đối chiếu round-trip đủ 256 giá trị byte, đầu vào sai kiểu và chuỗi hex sai định dạng. Chưa tích hợp giao thức nhị phân thực tế.




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