【実務・中級編】 String.prototype.trimStart() / trimEnd() – JavaScript実践ガイド

こんにちは。チームのコードレビューをしていて、いまだに `replace(/^\s+/, ”)` なんて古い正規表現を見かけると、思わず赤ペンを持ちたくなるシニアエンジニアの私です。

君たちも、ユーザーが入力フォームに入れた前後の空白に悩まされた経験、一度や二度ではないはずだ。「とりあえず `.trim()` を使っておけ」という教えは正しい。だが、実務の現場では「先頭だけ」「末尾だけ」ピンポイントで削りたいというシチュエーションが確実にやってくる。

今回は、JavaScriptの文字列操作において意外と見落りがちな `String.prototype.trimStart()` と `String.prototype.trimEnd()` について、ブラウザの裏側の動きや実務での実践的な使い所を交えて徹底的に解説しよう。

—

なぜ `.trim()` では物足りないのか?

文字列の両端の空白を綺麗に消し去る `.trim()` は、ログインフォームのIDやパスワードの入力値チェックなどで毎日のように使っていることだろう。

しかし、考えてみてほしい。例えば、エディタの入力補完機能や、複数行にわたるテキストエリアのデータを整形するパーサーを書いているとき、「末尾の改行やホワイトスペースは残したいが、先頭のインデントだけは綺麗にこそげ落としたい」という場面に出くわす。

そんなとき、従来の私たちはどうしていたか?

// 昔ながらの正規表現によるアプローチ
const dirtyText = ” Hello, Frontend Architecture!”;
const cleanText = dirtyText.replace(/^\s+/, ”);

動く。動くには動くが、これ、少し大げさだし、正規表現のパースコストや可読性の観点から見ても、モダンなJSの書き方とは言えない。何より、コードレビューで「これ、なんで正規表現なの?」と聞かれたときにスマートに答えられるか?

そこで登場するのが、ES2019で標準化された `trimStart()`(およびエイリアスの `trimLeft()`)と `trimEnd()`(同 `trimRight()`)だ。

—

ブラウザの裏側で何が起きているのか?(仕様とパフォーマンス)

ここで少し立ち止まって、JavaScriptエンジン(V8など)がこれらをどう処理しているか、その裏側の話をしておこう。

`trimStart()` や `trimEnd()` は、対象の文字列のメモリ走査を片方向だけに限定できるという密かなメリットがある。
通常の `.trim()` は、文字列の「先頭」と「末尾」の両方をスキャンし、空白ではない文字にぶつかるまでインデックスを前後に進める。

一方、`trimStart()` は文字通り先頭から非空白文字が現れるまでスキャンし、ヒットした瞬間にそこから後ろの文字列のメモリ参照(あるいは新しいプリミティブ文字列の生成)を行う。末尾の走査を完全にスキップできるため、巨大なテキストデータを扱うパーサーなどでは、ほんのわずかではあるがCPUサイクルとメモリ効率の最適化に寄与する。

「たかが空白の削除」と侮るなかれ。フロントエンドで数万文字のMarkdownやログデータをリアルタイムに整形するようなリッチなUIを組む場合、こうした細かいメソッドの選択が、メインスレッドのブロッキングを防ぐ鍵になるのだ。

—

実務で使える!キレイなサンプルコード

百聞は一見にしかず。現場でそのまま使える実用的なスニペットを用意した。
ブラウザのコンソールにでも貼り付けて、その動きを確認してみてほしい。

/

  • 現場でよくあるユースケース:
  • ユーザーが入力したコードスニペットの「先頭の無駄なインデント」だけを消去し、
  • 改行コードや末尾の構造はそのまま保持するパーサーの例

/

const rawUserCode = `
function secretOfArchitecture() {
console.log(“Keep your code clean.”);
}
`;

// 先頭の空白・改行のみを除去する
const trimmedStartCode = rawUserCode.trimStart();

console.log(“— 従来の .trim() の場合(末尾の改行も消える) —“);
console.log(JSON.stringify(rawUserCode.trim()));
// 出力結果: “function secretOfArchitecture() {\n console.log(\”Keep your code clean.\”);\n }”

console.log(“— trimStart() の場合(末尾のインデントや改行は保持される) —“);
console.log(JSON.stringify(trimmedStartCode));
// 出力結果: “function secretOfArchitecture() {\n console.log(\”Keep your code clean.\”);\n }\n”

もう一つ、実務でありがちなのが「CSVやAPIから送られてきた不整形なデータのクリーニング」だ。

/

  • APIから返却された配列データの各要素に対して、
  • 末尾の不要なホワイトスペースだけを安全に削り取る処理

/
const rawApiResponse = [
“Item A “,
“Item B\t\t”,
“Item C ”
];

// 末尾の半角スペースやタブ文字だけを綺麗に削る
const sanitizedResponse = rawApiResponse.map(item => item.trimEnd());

console.log(sanitizedResponse);
// 出力: [“Item A”, “Item B”, “Item C”]
// ※もし要素の先頭に意図的なスペースがあっても、それは保持されるため安全。

このように、「どこを削るべきか」の意図がコードのリーダability(可読性)として明確になるのが、これらのメソッドの最大の美しさだ。

—

シニアからの実践的なアドバイス(ベストプラクティス)

1. エイリアスについて:`trimLeft` / `trimRight` は避けるべし
歴史的な経緯(Webkitが独自実装していた名残)により、`trimStart` には `trimLeft` というエイリアスが存在する。しかし、仕様(ECMAScript)として正式に推奨されているのは `trimStart` と `trimEnd` だ。チームのコードベースの一貫性を保つためにも、新しいコードを書く際は必ず `trimStart` / `trimEnd` を選択しよう。

2. 型安全性を忘れない
TypeScriptを使っていれば防げるが、素のJavaScript環境でAPIレスポンスなどを扱う際、値が `null` や `undefined` である可能性を忘れてはいけない。いきなり `value.trimStart()` を呼ぶと、お馴染みの `TypeError: Cannot read properties of undefined` が爆誕する。
オプショナルチェイニング (`?.`) を組み合わせて、防衛的なコードを書くのがプロの作法だ。

const safeValue = userInput?.trimStart() ?? ”;

—

まとめ

`trimStart()` と `trimEnd()` は、派手な機能ではない。だが、こうした標準仕様の引き出しをどれだけ正確に、そして深く理解しているかが、ジュニアから中級、そしてシニアへとステップアップするための境界線になる。

次にコードを書くとき、「あ、ここは先頭だけ削りたいから `trimStart()` が最適だな」と秒で判断できるエンジニアになってほしい。期待しているぞ。

コメント

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