Lập trình · 23/10/2026

JavaScript toString(16): Radix Conversion Is Not a Byte Format

value.toString(16) does not guarantee two hexadecimal digits representing one byte. Negative values retain a sign, larger numbers need more digits and fractions may remain fractional. Define both the numeric domain and text format before exchanging byte values.

JavaScript toString(16): đổi cơ số chưa phải định dạng một byte

value.toString(16) does not guarantee two hexadecimal digits representing one byte. Negative values retain a sign, larger numbers need more digits and fractions may remain fractional. Define both the numeric domain and text format before exchanging byte values.

1. Radix conversion produces a number representation

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 accepts a radix. It does not automatically turn -1 into a two's-complement byte ff, add a 0x prefix or enforce fixed width.

Do not take the last two digits to hide out-of-range input without an explicit truncation policy. Turning 256 into 00 loses information. Rounding 1.5 likewise requires a separate decision.

2. Encode only the unsigned-byte domain

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

The helper accepts integer numbers from zero through 255 and emits exactly two lowercase hex digits without a prefix. Number.isInteger does not coerce numeric strings. Range validation makes the width a contract guarantee before padding.

Negative zero is treated as zero and encoded as 00. This contract does not preserve its sign. Signed-byte inputs need an explicit conversion policy rather than bypassing checks or masking invalid inputs with bitwise operations.

3. Validate the whole string before parsing

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

The regex requires exactly two ASCII hexadecimal digits, rejecting single digits, 0x prefixes, whitespace and trailing data. parseInt can stop at an invalid character and return a numeric prefix, so it is not sufficient for whole-input validation.

The decoder accepts both letter cases; the encoder emits lowercase. Thus fromHexByte(toHexByte(n)) preserves every byte value, but encoding decoded '0F' yields '0f'. This deliberately canonicalizes formatting instead of preserving every input string verbatim.

4. One byte does not define the entire protocol

These helpers do not determine multibyte endianness, text encoding, separators or packet structure. Sender and receiver must agree on those separately. A correctly formatted byte does not establish that an entire file or payload is valid.

The numeric range also does not validate business meaning. A byte can still represent an unsupported status or setting. Distinguish format failures from domain failures when reporting errors.

5. Review before formatting hex

  • Is the input an unsigned byte or another numeric type?
  • Are range, negative-value and fraction rules explicit?
  • Are width, prefix and letter case specified?
  • Does decoding validate the complete string?
  • Do tests cover boundaries and the required round-trip direction?

All six bilingual blocks ran with Node.js. Additional checks exercise every one of the 256 byte values, invalid types and malformed hexadecimal text. Real binary protocols were not integrated.

Discussion

Comments 0

Sign in to comment

You need an account to join the discussion and reply to other readers.

Sign inRegister

No comments yet. Be the first to share your thoughts.