文字列比較の「沼」から抜け出す:localeCompare() を極めるための実践ガイド
フロントエンドの現場で、「ユーザー名」や「商品リスト」をソートする機能を作るとき、あなたはどうしていますか?
「とりあえず `sort()` を使えばいいか」と軽い気持ちで `[‘a’, ‘B’, ‘c’].sort()` を書いた瞬間、あなたは知らないうちに「文字列比較の沼」に足を踏み入れています。JavaScriptの標準的な比較(`>` や `<`)は、文字コード(UTF-16のコードポイント)に基づいています。つまり、大文字と小文字が混ざった瞬間に期待通りの順序にはならないし、日本語の漢字やアクセント付きのアルファベットが混ざると、もはやカオスです。 今日は、そんな泥臭い「文字列比較」の悩みを一撃で解決する、プロ御用達のメソッド `localeCompare()` について深掘りしていきます。 ---
なぜ `localeCompare()` なのか?
結論から言うと、「人間が期待する並び順」を正確に再現できるのは、ブラウザの言語エンジンが提供する `localeCompare()` だけだからです。
ブラウザの裏側では、ECMAScriptが定義する「Intl(国際化)API」が動いています。これは各OSのロケール設定と連携し、「この言語圏なら、この文字とこの文字はどういう順序になるべきか」を計算しています。これを自前で実装しようなどと考えてはいけません。それは車輪の再発明どころか、茨の道です。
—
実践:現場で即戦力となるオプション活用術
`localeCompare()` が真価を発揮するのは、第2引数以降のオプションです。これを知っているだけで、ソートの実装レベルが一段階上がります。
1. 数値を自然な順序で扱う (`numeric: true`)
デフォルトのソートだと `file10.txt` が `file2.txt` より前に来てしまいますよね。これを解決するのが `numeric` です。
const files = [‘file10.txt’, ‘file2.txt’, ‘file1.txt’];
// 通常のソートだと [‘file1.txt’, ‘file10.txt’, ‘file2.txt’] になる
// オプション指定で人間の直感に合わせる
files.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
console.log(files); // [‘file1.txt’, ‘file2.txt’, ‘file10.txt’]
2. 大文字小文字やアクセントの無視 (`sensitivity`)
「検索機能で大文字小文字を区別したくない」「アクセント記号(é や ä)の有無を気にせずソートしたい」という場面は多いはずです。
const names = [‘résumé’, ‘Resume’, ‘resume’];
// base: 文字の基本形のみを比較(アクセントや大文字小文字を無視)
names.sort((a, b) => a.localeCompare(b, ‘en’, { sensitivity: ‘base’ }));
console.log(names);
// 結果: [‘resume’, ‘résumé’, ‘Resume’]
// ※これらはすべて「同じもの」として扱われるため、安定ソートが維持される
—
現場の知恵:パフォーマンスへの意識
ここで一つ、シニアとしてのアドバイスを。`localeCompare()` は非常に強力ですが、大量のデータを扱うループ内で安易に呼び出すのは避けてください。
なぜなら、`Intl` インスタンスの生成はコストがかかる処理だからです。例えば数万件のリストを一気にソートする場合、毎回 `localeCompare` を呼び出すとメインスレッドがブロックされる可能性があります。
ベストプラクティス:Intl.Collator の活用
もしパフォーマンスがボトルネックになるなら、`Intl.Collator` を事前にインスタンス化して使い回すのが定石です。
// 大量のデータ処理用:Collatorをキャッシュして再利用する
const collator = new Intl.Collator(‘ja’, { numeric: true, sensitivity: ‘base’ });
const longList = [‘データ10’, ‘データ2’, ‘データ1’];
// 直接メソッドを呼ぶのではなく、インスタンスの compare 関数を使う
longList.sort(collator.compare);
console.log(longList); // [‘データ1’, ‘データ2’, ‘データ10’]
—
まとめ:明日から使えるテクニック
文字列比較は、一見地味ですが、UIの品質を左右する非常に重要な要素です。
- 単純な比較は捨てる: `>` や `<` はコードポイント比較。UIソートには `localeCompare` を使う。
- オプションを味方にする: `numeric: true` はファイル名や数値を含むIDのソートに必須。
- 大規模データは Collator: ループ内での多用を避け、`new Intl.Collator` でインスタンスを使い回す。
JavaScriptは、仕様の裏側にこうした「人間側の都合」を解決するための強力な武器を隠し持っています。公式ドキュメントを眺めるだけではなく、こうして「現場の課題をどう解決するか」という視点でAPIを眺めると、フロントエンド開発がもっと面白くなるはずです。
さあ、あなたの書いているそのソートロジック、今日から少しだけスマートに書き換えてみませんか?

コメント