フロントエンドの現場で、「文字列の全置換」というありふれた処理に頭を悩ませた経験はないだろうか?
かつて、僕らが `replace()` メソッドで全置換をするために、正規表現のグローバルフラグ(`/g`)を必死に書いていた時代を思い出す。あれは便利だったが、同時に「特殊文字のエスケープ漏れ」という地雷を踏みやすい厄介な仕様でもあった。
ES2021で `replaceAll()` が登場したとき、多くのエンジニアは「これでやっと楽になれる」と喜んだものだ。だが、この2つの挙動の違いを深く理解していないと、いざという時に痛い目を見る。今日は、その「泥臭い差異」と、現代のフロントエンドにおける正しい使い分けについて話そう。
—
1. そもそも `replaceAll` とは何者か?
`replaceAll()` は、単純な文字列を検索対象にして、ヒットする全ての箇所を一括で変換してくれるメソッドだ。
最大の特徴は、「第一引数に文字列を渡した場合、それを正規表現として解釈しない」という点にある。これまでの `replace()` に第一引数として文字列を渡すと、最初に見つかった1箇所しか置換されなかった。それを回避するために、無理やり正規表現を作って `new RegExp()` でエスケープ処理を書いていた……そんな苦労はもう不要だ。
実務で見る「旧来の罠」と「replaceAll」の対比
const text = “JSは最高。JSは世界を動かす。”;
// 昔のやり方:replaceで全置換しようとしてハマるパターン
// これだと「JS」の箇所しか置換されない(グローバル指定がないため)
console.log(text.replace(“JS”, “JavaScript”));
// 結果: “JavaScriptは最高。JSは世界を動かす。”
// 昔のやり方:正規表現を使うパターン
// 文字列の中に「.」や「」などの特殊文字が含まれているとエスケープが必要になり、コードが汚れる
const pattern = new RegExp(“JS”.replace(/[.+?^${}()|[\]\\]/g, ‘\\$&’), ‘g’);
console.log(text.replace(pattern, “JavaScript”));
// 現代のやり方:replaceAllを使う
// 直感的で、特殊文字を気にしなくていいのが最大のメリット
console.log(text.replaceAll(“JS”, “JavaScript”));
// 結果: “JavaScriptは最高。JavaScriptは世界を動かす。”
—
2. 正規表現による置換との「決定的な違い」
では、`replaceAll()` が出たからといって、正規表現による置換が不要になったわけではない。「動的なパターン」や「複雑な条件」を扱うなら、依然として正規表現が必要だ。
ここで注意すべき「裏側の挙動」がある。
- `replaceAll()` に正規表現を渡す場合:
ES2021以降、`replaceAll()` に正規表現を渡すことは可能だが、その正規表現には必ずグローバルフラグ (`/g`) が必要だ。 これがないと、JavaScriptは `TypeError` を投げて処理を止める。これは、「全置換を意図しているなら、明示的にグローバルであることを示せ」という言語設計側の強い意志を感じる。
- ブラウザの裏側の処理(エンジンレベルの話):
V8エンジン(Chrome/Node.js)等の実装では、文字列リテラルを渡された `replaceAll` は内部的に `String.prototype.indexOf` を用いたループ処理や、最適化された文字列探索アルゴリズムで動作する。一方、正規表現を用いた置換は、専用の正規表現エンジンを起動してステートマシンを走らせるコストがかかる。
結論:単純な文字列置換なら `replaceAll` の方が圧倒的に安全で、可読性も高い。
—
3. 実践:現場で使えるベストプラクティス
現場で書くコードでは、以下の基準で選ぶのがスマートだ。
1. 静的な文字列の置換: `replaceAll()` を使う。エスケープの心配がないため、ユーザー入力値などを扱う際も安全だ。
2. パターンマッチングが必要な場合: `/g` フラグ付きの正規表現を使い、`replace()` を呼ぶ(または `replaceAll()` に渡す)。
/
- 実践的なTips:ユーザー入力を安全に置換する
/
const sanitizeInput = (input, target, replacement) => {
// ユーザーが入力した文字列をそのまま置換対象にする場合
// replaceAllなら正規表現の特殊文字によるバグを気にする必要がない
return input.replaceAll(target, replacement);
};
// 逆に、パターンとして扱いたい場合は正規表現を使う
// 例:連続する空白を1つのスペースに置換する
const normalizeSpaces = (str) => {
return str.replace(/\s+/g, ‘ ‘);
};
console.log(normalizeSpaces(“Hello World”)); // “Hello World”
—
最後に:エンジニアとしての矜持
「新しいメソッドが出たから古い手法はすべてゴミ」という考え方は捨てよう。`replace` も `replaceAll` も、それぞれが適した「戦場」を持っている。
正規表現をこねくり回してパズルを解くようなコードは、時として後続のエンジニアを苦しめることになる。「意図が明確なコード」こそが、フロントエンド開発における最強のアーキテクチャだ。
皆さんのチームでも、文字列置換のコードを見かけたら「これは `replaceAll` でスッキリ書けるのではないか?」という視点をぜひ持ってみてほしい。それだけで、コードベースの治安はグッと良くなるはずだ。
また何か悩みがあればいつでも相談してくれ。現場のコードを、より良くしていこう。

コメント