【入門編】 codePointAt() と charCodeAt() の使い分け – JavaScript実践ガイド

こんにちは!フロントエンドの現場を渡り歩いているチーフアーキテクトの私です。

JavaScriptで文字列を扱っていると、「文字のひと文字を取り出したい!」という場面に必ず直面しますよね。そんなときにお世話になるのが `charCodeAt()` というメソッドです。

「よし、これで文字コードが取れるぞ!」
……と、意気揚々とコードを書いたあなた。もしや、絵文字やちょっと珍しい漢字を扱ったときに、文字化けならぬ「謎の数字(不完全なデータ)」が返ってきて頭を抱えていませんか?

「あれ? 私の書いたコード、どこか間違ってる……?」

大丈夫ですよ、安心してください。あなたのせいではありません。これはJavaScriptの歴史と、文字というものの複雑さが生んだ、フロントエンド開発者なら誰もが一度は通る「小さな罠」なんです。

今日は、レガシーな `charCodeAt()` と、現代の救世主である `codePointAt()` の違いについて、身近なたとえ話を交えながら、とことん優しく解き明かしていきましょう!

—

1. 文字の世界の「測り方」:定規とメジャーのたとえ

まず、コンピュータが文字をどう見ているかのお話から始めますね。
コンピュータにとって、文字はすべて「数字」です。「あ」はこの数字、「A」はこの数字、という風に、辞書のように番号が割り振られています(これを文字コードと呼びます)。

JavaScriptで文字の「背番号」を知るために用意されたのが、`charCodeAt()` と `codePointAt()` です。

ここで、身近な道具にたとえてみましょう。

  • `charCodeAt()` は「15cmの短いプラスチック定規」
  • 大昔のコンピュータの世界で作られた、由緒正しい定規です。
  • 普通のアルファベットやひらがななら、この定規の長さ(16ビット)で余裕で測れます。
  • `codePointAt()` は「どんなに長いものでも測れる最新のメジャー」
  • 世界中のあらゆる文字、さらには最近の大人気な「絵文字」や「珍しい漢字」まで、どんなに大きな番号でも正確に測れる現代のメジャーです。

「えっ、じゃあ最初から長いメジャーを使えばいいじゃない!」その通りです。でも、なぜ昔の定規(`charCodeAt()`)がいまだに現役で、そして私たちを悩ませるのか。そこにはちょっぴり切ない理由があるのです。

—

2. つまずきの元凶!「サロゲートペア」ってなに?

JavaScriptが生まれた大昔、世界中の文字は「1文字 = ひとつの部屋(16ビット)」にすっぽり収まると想定されていました。

しかし、世の中は広いです。漢字だけでも数万字ありますし、今や世界中で愛される絵文字(🎉や🐈など)もあります。これらは、古い定規(16ビットの部屋)には入りきらないほど、大きな背番号を持っています。

そこでコンピュータの世界の偉い人たちは考えました。
「入らないなら、2つの部屋を合体させて1文字を表現しよう!」

この「2つの部屋をペアにしてひとつの文字を表す仕組み」を、サロゲートペアと呼びます。

悲劇のドラマ:`charCodeAt()` の勘違い

ここで、絵文字の「🐈(ネコ)」を例に見てみましょう。
このネコの絵文字、実はコンピュータの裏側では「2つの部屋(前半のパーツと後半のパーツ)」に分かれて入っています。

もし、このネコちゃんに対してレガシーな `charCodeAt()` を使うと、どうなるでしょうか?

  • 「ネコちゃんの全体の背番号を知りたいな!」と思って `charCodeAt(0)` を使う。
  • 定規の長さが足りないため、「前半のパーツの部屋番号」だけを中途半端に覗き見してしまう。
  • 結果として、ネコちゃん本来の番号とは全く違う、「謎の数字」が返ってくる。

これが、文字化けや予期せぬバグを引き起こす原因なんです。「文字の長さを数えたら、なぜか『1文字』なのに『2』って返ってきた!」という絶望を味わったことはありませんか? まさにそれがこのサロゲートペアのいたずらです。

—

3. 救世主登場! `codePointAt()` の優しい世界

そんなサロゲートペアの悲劇をスパッと解決してくれるのが、現代のJavaScriptが誇る `codePointAt()` です。

こいつは非常に優秀です。もし目の前の文字が2つの部屋に分かれていても、「あ、これはサロゲートペアだな」と瞬時に見抜き、合体させて正しい本当の文字コード(コードポイント)を返してくれます。

百聞は一見に如かず。実際にコードを書いて、その違いをこの目で確かめてみましょう!

実際に動かしてみよう(サンプルコード)

以下のコードを、お使いのブラウザの開発者ツール(Console)などにそのまま貼り付けて実行してみてください。

// 普通のアルファベット(サロゲートペアではない文字)
const normalChar = ‘A’;

console.log(‘— 普通の文字の場合 —‘);
console.log(normalChar.charCodeAt(0)); // 65 (問題なく取れます)
console.log(normalChar.codePointAt(0)); // 65 (こちらもバッチリ!)

// 大人気の絵文字(サロゲートペアの文字)
const emojiChar = ‘🐈’; // 猫の絵文字

console.log(‘— 絵文字(サロゲートペア)の場合 —‘);

// レガシーな charCodeAt だと…?
console.log(emojiChar.charCodeAt(0));
// 出力結果: 55357 (※これはネコの本当の番号ではありません!前半の断片です)

// 現代的な codePointAt なら…?
console.log(emojiChar.codePointAt(0));
// 出力結果: 128008 (※これがネコちゃんの正しい背番号です!)

おぉ……! `codePointAt(0)` だと、絵文字であってもちゃんと正しい番号(128008)が返ってきましたね。これなら安心してお仕事に使えます。

—

4. チーフアーキテクトが教える、実務での使い分けの極意

「じゃあ、明日からのコードは全部 `codePointAt()` に書き換えればいいんだね?」

……と意気込みたくなるところですが、そこは現場のプロ。少しだけ冷静になりましょう。実務でのスマートな使い分けの指針を授けます。

① 基本は `codePointAt()` を選ぼう(特にモダンなWebアプリ)

ユーザーが入力フォームに絵文字を入れたり、多言語(特殊な漢字や記号など)を扱う現代のWebアプリケーションにおいて、文字列を安全に解析したい場合は、迷わず `codePointAt()` を採用してください。文字の欠損や予期せぬバグを防ぐための、私たちエンジニアの優しさです。

② じゃあ `charCodeAt()` はもう捨てていいの?

いいえ、レガシーなメソッドにもまだ居場所はあります。
例えば、プロジェクトの要件として「入力されるのはアルファベットと数字(半角英数)だけであることが絶対に保証されている」というレガシーなシステムや、パフォーマンスが極限まで求められる特定の内部処理においては、古くから最適化されている `charCodeAt()` が使われることもあります。
また、古いライブラリのコードリーディングをする際にも、「あ、これは古い定規を使ってるんだな」と気づけるだけで十分です。

—

おわりに:文字列操作は、文字への思いやりから

JavaScriptの文字まわりの仕様は、歴史的ないきさつもあり、正直ちょっと複雑で泥臭い部分があります。でも、その背景にある「なぜこのメソッドがあるのか」を知ることで、コードを書くときの視界がパッと明るくなりますよね。

今日学んだ `codePointAt()` は、画面の向こう側にいるユーザーが打ってくれた大切な絵文字や文字を、欠けることなく正しく受け止めるための「優しいメジャー」です。

あなたの書くコードが、画面の向こうのユーザーにそっと寄り添う温かいものでありますように。
それでは、また次の現場でお会いしましょう! チーフアーキテクトの私でした。

コメント

タイトルとURLをコピーしました