Stringの静的メソッドを制する:fromCharCodeとfromCodePointの「深淵なる違い」
フロントエンドの現場で「文字コードから文字列を生成する」という処理、意外と遭遇しますよね。アイコンフォントの生成、暗号化処理のデコード、あるいは特定のバイナリデータをパースする際など。
多くの開発者が `String.fromCharCode` で何となく済ませてしまっていますが、実はそこに「歴史的負債」と「現代的な解決策」の境界線が隠れています。今回は、中級エンジニアが絶対に知っておくべき `String.fromCharCode` と `String.fromCodePoint` の決定的な違いと、なぜ後者を使うべきなのかを深掘りします。
—
1. String.fromCharCodeの「古き良き限界」
`String.fromCharCode` は、JavaScriptの黎明期から存在するメソッドです。UTF-16のコードユニットを指定して文字列を組み立てます。
// A, B, C という文字列を作る
const str = String.fromCharCode(65, 66, 67);
console.log(str); // “ABC”
シンプルですね。しかし、ここで問題になるのが「サロゲートペア」です。
JavaScriptの文字列はUTF-16で表現されています。初期のUnicodeは16ビット(65,536文字分)で収まると考えられていましたが、絵文字などの特殊文字が増えるにつれ、16ビット(コードユニット)を2つ組み合わせて1文字を表現する「サロゲートペア」という仕組みが必要になりました。
`fromCharCode` は、16ビット単位でしか処理ができません。そのため、サロゲートペアが必要な文字(例えば「𠮷」のような漢字や、最新の絵文字)を扱うと、途端に壊れます。
// 「𠮷」はコードポイント 0x20BB7。
// fromCharCode で扱おうとすると…
console.log(String.fromCharCode(0x20BB7)); // 期待値とは異なる文字(0x0BB7に切り捨てられる)
現場のバグ調査で「なぜか絵文字が文字化けする」「特殊な漢字だけ検索にヒットしない」というケースの多くは、この古いメソッドが原因だったりします。
—
2. fromCodePointで「現代の常識」をインストールする
ES2015(ES6)で導入された `String.fromCodePoint` は、まさにこのサロゲートペア問題を解決するために生まれてきました。
こいつは引数に「コードポイント(Unicodeの論理的な番号)」を直接渡せます。内部で自動的にサロゲートペアが必要かどうかを判断し、適切なビット列に変換してくれるのです。
/
- 実践的な比較:絵文字「🚀」を出力してみる
/
const emojiCode = 0x1F680;
// × fromCharCodeだと…
console.log(String.fromCharCode(emojiCode)); // 謎の記号が出力される
// ◎ fromCodePointなら!
console.log(String.fromCodePoint(emojiCode)); // “🚀” が正しく表示される
なぜこれが重要なのか?
ブラウザのエンジン(V8など)の裏側を覗くと、`fromCodePoint` は入力された数値をチェックし、それがBMP(基本多言語面)を超えているかどうかを計算しています。もし超えていれば、適切に上位サロゲートと下位サロゲートに分割してメモリに展開する――という複雑な処理を、私たちが意識することなく一瞬で実行してくれています。
—
3. 実務で使えるベストプラクティス
現場でこの知識をどう活用すべきか? 結論はシンプルです。「文字コードから文字列を作るなら、例外なく `fromCodePoint` を使うこと」。
特に、外部APIから取得した数値配列を文字列に復元したり、動的にDOMのコンテンツを生成するシーンでは、迷わずこちらを選んでください。
以下は、配列として受け取ったコードポイント群を安全に文字列化する、実用的なユーティリティ関数の例です。
/
- 数値配列から安全に文字列を生成する堅牢な関数
- @param {number[]} codePoints
- @returns {string}
/
function createStringFromPoints(codePoints) {
try {
// スプレッド演算子で展開して渡すのが現代的
return String.fromCodePoint(…codePoints);
} catch (e) {
console.error(“無効なコードポイントが含まれています:”, e);
return “”;
}
}
// 使用例
const codes = [72, 101, 108, 108, 111, 32, 0x1F30D]; // “Hello 🌍”
console.log(createStringFromPoints(codes));
—
最後に:シニアからのアドバイス
「動けばいい」というコードは、数ヶ月後の自分やチームメンバーを確実に苦しめます。特に文字列操作は、後から「特定の環境でだけ文字化けする」といった、再現性の低い地獄のようなバグを生みやすい領域です。
JavaScriptの歴史的な経緯を知ることは、単なる知識の蓄積ではありません。「なぜ今の仕様になっているのか」という設計思想への理解です。
これからは `fromCharCode` を見かけたら、「お、ここは歴史的な遺産だな。現代的な `fromCodePoint` に置き換えておこう」とリファクタリングの対象として捉えてみてください。その小さな積み重ねが、堅牢なアプリケーションを作る唯一の近道です。
さあ、明日からのコーディングで、コードの「質」を一段階引き上げていきましょう!

コメント