Four bits, one digit
Long rows of 0s and 1s are hard to read. Hexadecimal uses 16 digits (0–9, A–F), and one hex digit is exactly four bits — so a byte is always two hex digits: 11111111 is FF. Colours like #FF8800, memory addresses and file dumps all use hex.
From characters to bytes
Every character has a number (its *code point*): A is 65, é is 233, न is 2344, 😀 is 128512. UTF-8 stores small numbers in one byte (so English text stays compact) and bigger ones in 2, 3 or 4 bytes. The first bits of each byte say how many bytes belong together.
const DIGITS = "0123456789ABCDEF";
function toHex(n) {
if (n === 0) return "0";
let out = "";
while (n > 0) {
out = DIGITS[n % 16] + out;
n = Math.floor(n / 16);
}
return out;
}
function utf8Bytes(text) {
const bytes = [];
for (const ch of text) {
const cp = ch.codePointAt(0);
if (cp < 0x80) bytes.push(cp);
else if (cp < 0x800) bytes.push(0xc0 | (cp >> 6), 0x80 | (cp & 0x3f));
else if (cp < 0x10000) bytes.push(0xe0 | (cp >> 12), 0x80 | ((cp >> 6) & 0x3f), 0x80 | (cp & 0x3f));
else bytes.push(0xf0 | (cp >> 18), 0x80 | ((cp >> 12) & 0x3f), 0x80 | ((cp >> 6) & 0x3f), 0x80 | (cp & 0x3f));
}
return bytes;
}