文字列の「検索」を一言でいうと
文字列の検索は、
「この文字(文字列)が含まれているか?」
「含まれているなら、どの位置にあるか?」
を調べることです。
JavaScript では、そのために主にindexOf と includes という 2 つのメソッドを使います。
indexOf は「位置が知りたいとき」includes は「含まれているかどうかだけ知りたいとき」
このイメージを持っておくと整理しやすいです。
ここが重要です。
条件分岐(if)と組み合わせたとき、
indexOf は「位置 or -1」、includes は「true / false」
という結果を返す、という違いをしっかり押さえると、一気に使い分けが楽になります。
indexOf の基本:最初に見つかった位置(インデックス)を返す
indexOf の基本構文と戻り値
indexOf の書き方はこうです。
文字列.indexOf(検索したい文字列)
JavaScript戻り値は「最初に見つかった位置のインデックス」です。
もし見つからなければ -1 が返ってきます。
例を見てみましょう。
const text = "JavaScript";
console.log(text.indexOf("Java")); // 0
console.log(text.indexOf("Script")); // 4
console.log(text.indexOf("a")); // 1(最初に見つかった "a" の位置)
console.log(text.indexOf("z")); // -1(見つからない)
JavaScript"JavaScript" のインデックスはこうなっています。
J(0) a(1) v(2) a(3) S(4) c(5) r(6) i(7) p(8) t(9)
"Java" は 0 から始まる"Script" は 4 から始まる"a" は最初に 1 の位置にある
だから上のような結果になるわけです。
見つからないときは -1 になる(ここが大事)
indexOf は、検索対象が見つからないときに -1 を返します。
const text = "hello";
console.log(text.indexOf("x")); // -1
JavaScriptここで 0 や null や undefined ではなく、
必ず -1 という値になります。
ここが重要です。
「見つかったかどうか」を indexOf で判断するときは、=== -1 か !== -1 を使う。if (text.indexOf("a")) { ... } のように “そのまま if に突っ込む” のはバグの元です。
「見つかったかどうか」を indexOf で書く場合
例えば、「text に "a" が含まれているか?」を調べたいとします。
間違った書き方はこうです。
if (text.indexOf("a")) {
// これだと index が 0 のとき(先頭にあるとき)に false とみなされてしまう
}
JavaScriptindexOf が 0 を返した場合、0 は falsy(false 相当)なので if に入らなくなります。
正しい書き方はこうです。
if (text.indexOf("a") !== -1) {
console.log("a が含まれています");
} else {
console.log("a は含まれていません");
}
JavaScriptもしくは逆向きに、
if (text.indexOf("a") === -1) {
console.log("a は含まれていません");
}
JavaScriptのように書きます。
indexOf の応用:検索開始位置(第2引数)
第2引数で「どこから検索を始めるか」を指定できる
indexOf には、第2引数を渡すことができます。
文字列.indexOf(検索文字列, 開始位置)
JavaScript開始位置より前の部分は無視して、
そこから後ろだけを対象に検索します。
例:
const text = "banana";
// b(0) a(1) n(2) a(3) n(4) a(5)
console.log(text.indexOf("a")); // 1 (最初の a)
console.log(text.indexOf("a", 2)); // 3 (インデックス 2 以降で最初の a)
console.log(text.indexOf("a", 4)); // 5 (インデックス 4 以降で最初の a)
console.log(text.indexOf("a", 6)); // -1 (6 以降には a がない)
JavaScript「1 個目の a」「2 個目の a」「3 個目の a」と順番に探したいときなどに使えます。
全出現箇所を見つける処理のイメージ
例えば、「文字列中の "a" がある位置を全部知りたい」とします。
const text = "banana";
let index = text.indexOf("a");
while (index !== -1) {
console.log("a が見つかった位置:", index);
index = text.indexOf("a", index + 1);
}
JavaScript出力は
0, 2, 4
…ではなく、"banana" では
b(0) a(1) n(2) a(3) n(4) a(5)
なので、1, 3, 5 になります。
こうやって、「見つかった位置の次から再検索する」ことで、
複数の出現箇所を順番にたどることができます。
ここが重要です。
第2引数付き indexOf は「部分的にスキップしてから検索する」道具。
1回だけでなく、「次の位置からもう一度 indexOf」というパターンで、複数箇所を探せる。
includes の基本:「含まれているかどうか」だけが知りたいとき
includes の基本構文と戻り値
includes の書き方はこうです。
文字列.includes(検索したい文字列)
JavaScript戻り値はシンプルで、
含まれていれば true、含まれていなければ false です。
例:
const text = "JavaScript";
console.log(text.includes("Java")); // true
console.log(text.includes("Script")); // true
console.log(text.includes("java")); // false(大文字小文字は区別される)
console.log(text.includes("Python")); // false
JavaScriptindexOf で書いていた「含まれているか判定」を、includes なら素直に書ける
さきほどの「a が含まれているか?」のチェックをincludes で書くと、かなり読みやすくなります。
const text = "banana";
if (text.includes("a")) {
console.log("a が含まれています");
} else {
console.log("a は含まれていません");
}
JavaScriptこれだけです。
indexOf だと:
if (text.indexOf("a") !== -1) { ... }
JavaScriptとなり、!== -1 の意味を知らないと「何をやっているのか」が分かりにくいですよね。
ここが重要です。
「含まれているかどうか」だけを知りたいときは includes のほうが明らかに読みやすい。
indexOf の -1 を意識せずに済むので、バグも減ります。
includes も第2引数で開始位置を指定できる
includes にも第2引数があります。
文字列.includes(検索文字列, 開始位置)
JavaScriptindexOf と同じように、そこから後ろだけを対象に検索します。
const text = "banana";
// b(0) a(1) n(2) a(3) n(4) a(5)
console.log(text.includes("a", 2)); // true(インデックス2以降に a はある)
console.log(text.includes("a", 4)); // true(インデックス4以降にも a はある)
console.log(text.includes("a", 6)); // false(6 以降には a はない)
JavaScriptただし、「どこにあるか」までは教えてくれません。
あくまで「あるか/ないか」だけです。
indexOf と includes の使い分け
「位置」が欲しいなら indexOf
次のようなときは、indexOf が必要です。
特定の文字列が、どこに現れたか知りたい
見つかった位置からさらに操作したい(そこから先を slice したいなど)
複数の出現箇所を走査したい
例えば:
const url = "https://example.com/users/12345";
const index = url.indexOf("/users/");
if (index !== -1) {
const userId = url.slice(index + "/users/".length);
console.log(userId); // "12345"
}
JavaScript"/users/" がどの位置にあるか」を知って、その位置をもとにslice` しています。
こういう用途では indexOf が必須です。
「あるかどうか」だけなら includes
次のようなときは includes で十分です。
メールアドレスに "@" が含まれているかざっくりチェック
ファイル名に ".png" や ".jpg" が含まれているか確認
文章に NG ワードが含まれているかどうか
例:
const email = "user@example.com";
if (!email.includes("@")) {
console.log("メールアドレスの形式が怪しいです");
}
JavaScript位置情報まで必要ないので、
indexOf で !== -1 と書くより、
includes のほうが意図が伝わります。
includes を使えない環境の話(補足)
かなり古いブラウザ(古い IE など)では includes が使えないことがありましたが、
現代の開発ではほぼ気にしなくて大丈夫です。
もしどうしても includes が使えない環境を相手にするなら、indexOf(...) !== -1 で代替できる、と覚えておけば OK です。
ここが重要です。
基本方針としては
「位置が必要 → indexOf」
「存在チェックだけ → includes」
と覚えておけば、ほとんどのケースを迷わず書き分けられます。
大文字・小文字の扱いに注意(どちらも区別する)
indexOf も includes も大文字・小文字を区別する
例を見てください。
const text = "JavaScript";
console.log(text.includes("java")); // false
console.log(text.indexOf("java")); // -1
JavaScript"JavaScript" の中に "java"(全部小文字)は含まれていない、と判断されます。
"Java"(先頭だけ大文字)と "java" は、別物です。
大文字小文字を区別したくない場合(簡易版)
「大文字小文字を無視して検索したい」なら、
両方とも toLowerCase() や toUpperCase() で揃えてから検索します。
const text = "JavaScript";
const lower = text.toLowerCase();
console.log(lower.includes("java")); // true
console.log(lower.indexOf("script")); // 4
JavaScriptもちろん、検索する側も同様に揃えます。
const query = "JaVa";
const text = "javascript";
if (text.toLowerCase().includes(query.toLowerCase())) {
console.log("含まれています");
}
JavaScriptここが重要です。
indexOf も includes も、標準では「大小文字を区別する」。
大文字小文字を区別せず検索したいときは、toLowerCase() や toUpperCase() を組み合わせるのが基本パターンです。
初心者が本当に押さえるべきポイントまとめ
indexOf は「最初に見つかった位置」を返す。
見つからないときは -1。
「含まれているかどうか」の判定に使うときは、!== -1 / === -1 で比較する。
includes は「含まれているかどうかだけ」を返す。
結果は true / false なので、if 文と組み合わせると読みやすい。
2つ目の引数で「検索開始位置」を指定できるが、
位置が欲しいなら indexOf、存在チェックだけなら includes が向いている。
どちらも大文字小文字を区別する。
区別したくない場合は、toLowerCase() / toUpperCase() とセットで使う。
ここが重要です。
「場所が欲しいか」「存在だけ知りたいか」を自分に問う癖をつける。
場所が欲しいときに includes を選ぶと物足りないし、
存在だけ知りたいときに indexOf + !== -1 と書くとコードが読みにくくなる。
そこを意識して使い分けられるようになると、“文字列を相手にしたロジック” が一気に書きやすくなります。
小さな練習として、次のような課題を自分で書いてみると良いです。
- 文字列
text = "I like JavaScript and TypeScript"を用意する "JavaScript"が含まれているかをincludesで判定する"Script"の最初の位置をindexOfで求める"TypeScript"が含まれている場合だけ、その位置から最後までをsliceして表示する
この練習をすると、
「検索 → 判定 or 位置取得 → さらに部分取得」という、一連の流れが自分のものになっていきます。
