jsguides

String.prototype.charCodeAt()

charCodeAt(index)

The charCodeAt() method returns an integer representing the UTF-16 code unit at the specified index in a string. This method is essential when you need to work with the numeric representation of characters instead of the characters themselves.

Syntax

string.charCodeAt(index)
  • index: An integer representing the position of the character to retrieve. If omitted, defaults to 0. If negative or greater than or equal to length, returns NaN.
  • Returns: A number representing the UTF-16 code unit value (between 0 and 65535), or NaN if the index is out of bounds.

The index is zero-based and must reference a valid position within the string. Out-of-range indices produce NaN instead of throwing, consistent with JavaScript’s approach to boundary handling. The TypeScript declaration makes the parameter and return types explicit for type-checked codebases.

TypeScript Signature

interface String {
  charCodeAt(index: number): number;
}

The examples below use a short ASCII string where each character occupies a single code unit. This is the most common scenario — working with English text where numeric values map directly to familiar Unicode code points. Each charCodeAt call produces a predictable integer that you can inspect, compare, or store.

Basic Examples

const text = "Hello";

console.log(text.charCodeAt(0)); // 72  (H)
console.log(text.charCodeAt(1)); // 101 (e)
console.log(text.charCodeAt(4)); // 111 (o)
console.log(text.charCodeAt(5)); // NaN (out of bounds)

charCodeAt() vs codePointAt()

JavaScript strings use UTF-16 encoding. Most characters fit in a single 16-bit code unit (values 0–65535), but characters outside the Basic Multilingual Plane (BMP)—including many emojis—require surrogate pairs (two code units).

  • charCodeAt() returns the individual UTF-16 code unit (0–65535)
  • codePointAt() returns the full Unicode code point, properly handling surrogates
const emoji = "😀";

console.log(emoji.length);         // 2 (two UTF-16 code units)
console.log(emoji.charCodeAt(0)); // 55357 (0xD83D - high surrogate)
console.log(emoji.charCodeAt(1)); // 56832 (0xDE00 - low surrogate)
console.log(emoji.codePointAt(0)); // 128512 (0x1F600 - actual emoji codepoint)

Always use codePointAt() when processing emojis or international text.

Once you understand how individual characters map to numeric ranges, you can build fast, inline validators. The next example filters a string to only ASCII letters by testing each character’s code unit against the ranges for A–Z (65–90) and a–z (97–122).

Practical use case: character validation

function containsOnlyLetters(str) {
  for (let i = 0; i < str.length; i++) {
    const code = str.charCodeAt(i);
    // Check if character is A-Z (65-90) or a-z (97-122)
    if (!((code >= 65 && code <= 90) || (code >= 97 && code <= 122))) {
      return false;
    }
  }
  return true;
}

console.log(containsOnlyLetters("Hello")); // true
console.log(containsOnlyLetters("Hello!")); // false

Character codes also govern sort order in JavaScript. Uppercase letters (65–90) sit below lowercase letters (97–122) in the code table, so a naive code-point comparison produces case-sensitive ordering. This next example sorts by first-character code and reveals why “Banana” comes before “apple” in a code-unit sort.

Practical use case: custom sorting

// Sort strings by character codes (case-sensitive alphabetical)
const words = ["Banana", "apple", "Cherry"];

// Sort by first character code
words.sort((a, b) => a.charCodeAt(0) - b.charCodeAt(0));

console.log(words); // ["Banana", "Cherry", "apple"]
// B(66), C(67), a(97) - uppercase comes before lowercase

After extracting and comparing character codes, you may need to rebuild a string from numeric values. The inverse operation is String.fromCharCode(), which accepts one or more code units and returns the assembled string. This round-trip capability is handy for encoding, decoding, and programmatic text generation.

Converting back to characters

Use String.fromCharCode() to convert numeric code values back to characters:

const codes = [72, 101, 108, 108, 111];
const word = String.fromCharCode(...codes);

console.log(word); // "Hello"

The method’s behavior at boundary conditions is predictable but worth confirming. Negative indices, indices beyond the string length, and empty strings all return NaN without throwing. This design choice means you can iterate without wrapping calls in try/catch — just check for NaN after the call.

Edge Cases

const text = "test";

console.log(text.charCodeAt());     // 116 (defaults to index 0)
console.log(text.charCodeAt(0));    // 116 (t)
console.log(text.charCodeAt(-1));   // NaN (negative index)
console.log(text.charCodeAt(10));   // NaN (out of bounds)
console.log("".charCodeAt(0));      // NaN (empty string)

When charCodeAt() is the right tool

charCodeAt() is best when you are working with the raw UTF-16 code unit values of a string. That is useful for older protocols, custom parsers, and educational examples that need to show the underlying numeric representation of characters. It can also help when you are writing low-level validation code for a restricted character set.

For general text handling, though, it is easy to misuse because many visible characters are not a single code unit. Emoji, many symbols, and letters outside the basic Latin range may require more than one unit. If you are counting user-visible characters or processing multilingual text, move up to codePointAt() instead.

Practical Tradeoffs

The method is simple, but the simplicity can hide the encoding detail that makes JavaScript strings tricky. If you only need to check whether a string begins with a certain ASCII character, charCodeAt() is fine. If the input can contain surrogate pairs, combining marks, or other non-ASCII text, treat the numeric result as an implementation detail instead of a character-level guarantee.

That distinction matters when sorting, filtering, or rejecting input by character class. A code-unit based check may be fast, but it is not the same thing as full Unicode handling. Choosing the right method saves you from subtle bugs that only appear with real-world text.

Browser Compatibility

BrowserVersion
Chrome1+
Firefox1+
Safari1+
Edge12+
Node.js0.1.0+

Universal support across all JavaScript environments.

See Also