String.fromCharCode()

The inverse of charCodeAt, and 16-bit like its partner. For any code point above 0xFFFF it silently produces the wrong character — use fromCodePoint instead.

String static methodES1 (1997)Live demo
Common call
String.fromCharCode(65)
Returns
a string of one character per code unit
Replaces
nothing; it is the inverse of charCodeAt
Watch out
values above 0xFFFF are truncated, not rejected
String.fromCharCode(...codes...codes — Any number of UTF-16 code units. Each is taken modulo 65536 — no error is raised for a larger value. With no arguments you get an empty string.type: number · default: none)
→ string

Demo

Live evaluation
Try:
Inputs
codesnumber[]codes, comma separated
Output
String.fromCharCode(...[72, 105])
'Hi'

Each number becomes one UTF-16 code unit, so 72 and 105 spell 'Hi'. The fourth case is how you build an emoji with this method — by supplying both halves of the surrogate pair yourself, which is exactly the arithmetic fromCodePoint does for you. Passing the single code point 128512 instead would NOT work: it is above 0xFFFF, so it gets truncated to its low 16 bits and yields an unrelated character with no warning at all.

Parameters

NameTypeRequiredDescription
...codesnumberno (none)Any number of UTF-16 code units. Each is taken modulo 65536 — no error is raised for a larger value. With no arguments you get an empty string.

Return value

string — A string built from the given UTF-16 code units. Values above 0xFFFF are TRUNCATED to their low 16 bits rather than rejected.

Common patterns

Prefer fromCodePoint
Handles any code point, and rejects invalid ones.
String.fromCodePoint(0x1f600);
Decode a byte array
Fine for ASCII or Latin-1 data.
const text = String.fromCharCode(...bytes);
Large arrays need chunking
Spreading a huge array overflows the call stack.
let out = "";
for (let i = 0; i < b.length; i += 8192)
  out += String.fromCharCode(...b.subarray(i, i + 8192));

Examples

1. Spells Hi
String.fromCharCode(72, 105)
Returns
'Hi'
2. A surrogate pair
String.fromCharCode(55357, 56832)
Returns
'\u{1F600}'
3. Truncated, silently
String.fromCharCode(128512).codePointAt(0)
Returns
62976
4. fromCodePoint works
String.fromCodePoint(128512).codePointAt(0)
Returns
128512
5. No arguments
String.fromCharCode()
Returns
''
6. Round trip
String.fromCharCode('A'.charCodeAt(0))
Returns
'A'

Pitfalls

1. Values above 0xFFFF are truncated without warning
The worst kind of failure — no error, just a different character. Passing a real code point from codePointAt straight into fromCharCode mangles every emoji and every non-BMP script, and the corruption is only visible when someone looks at the output.
Wrong character
String.fromCharCode(128512).codePointAt(0)
62976
Use fromCodePoint
String.fromCodePoint(128512).codePointAt(0)
128512
2. Spreading a large array overflows the stack
Every element becomes a function argument, and engines cap that at roughly 65 000 to 125 000. Decoding a megabyte buffer in one call throws RangeError, so chunk it or use TextDecoder.
Too many arguments
String.fromCharCode(...hugeArray)
RangeError: Maximum call stack size exceeded
Use TextDecoder
new TextDecoder().decode(bytes)
handles any size, and UTF-8
3. It is a static, not an instance method
String.fromCharCode(...), never s.fromCharCode(...). The same slip as with Array.from and Array.of.
Not on instances
'a'.fromCharCode(65)
TypeError: "a".fromCharCode is not a function
Call on String
String.fromCharCode(65)
'A'
4. It is not a UTF-8 decoder
Feeding it raw UTF-8 bytes produces mojibake, because each byte becomes its own character instead of combining into multi-byte sequences. TextDecoder is the correct tool for byte data of unknown encoding.
Mojibake
String.fromCharCode(195, 169)
'é' // meant to be 'é'
Decode properly
new TextDecoder().decode(new Uint8Array([195, 169]))
'é'

When to use

Use it
  • Building a string from UTF-16 code units you already have
  • ASCII or Latin-1 byte data, where one byte is one character
  • Round-tripping with charCodeAt
Reach for something else
  • Any code point above 0xFFFF → fromCodePoint
  • Decoding UTF-8 or unknown byte encodings → TextDecoder
  • Very large arrays → chunk it, or TextDecoder
  • You have characters, not numbers → concat or a template literal

Notes

Complexity
O(n) in the number of arguments
Return
A new string
CPython impl
V8: Builtins-string-fromcharcode
Memory
Allocates the result string
Thread-safe
Single-threaded

FAQ

fromCodePoint, unless you specifically hold UTF-16 code units. It accepts the full Unicode range, builds surrogate pairs for you, and throws RangeError on an invalid value instead of silently truncating.

String.fromCodePoint(0x1f600);   // an emoji
String.fromCharCode(0x1f600);    // a different character entirely

History

ES1
fromCharCode present from the first version, when strings were assumed to be UCS-2.
ES2015
fromCodePoint added to build characters beyond the BMP correctly.