JavaScriptのindexOf()メソッドは、文字列や配列の中から特定の値を検索し、最初に見つかった位置(インデックス)を返します。見つからない場合は-1を返すため、「要素が存在するかどうか」の判定にも広く使われています。
この記事では、String.prototype.indexOf() と Array.prototype.indexOf() の両方の使い方から、includes()・find()・lastIndexOf() との違い、実務で頻出するパターン、よくあるミスまで体系的に解説します。
この記事で学べること
- String.prototype.indexOf() の基本構文と戻り値
- fromIndex(第2引数)を活用した検索テクニック
- Array.prototype.indexOf() と厳密等価比較の注意点
- includes() との違いと使い分け
- lastIndexOf()・find()・findIndex()・search() との比較
- 実務で使う頻出パターン(存在チェック・フィルタリング・出現回数カウント)
- indexOf() でハマりやすいミスと対策
String.prototype.indexOf() の基本
String.prototype.indexOf() は、文字列の中から指定した文字列(部分文字列)を検索し、最初に見つかった位置のインデックスを返します。見つからなければ -1 を返します。
構文
構文
str.indexOf(searchValue)
str.indexOf(searchValue, fromIndex)
| 引数 |
説明 |
| searchValue |
検索する文字列。空文字列 "" を渡すと fromIndex(省略時は0)を返す |
| fromIndex(省略可) |
検索を開始する位置(デフォルト: 0)。負の値を指定すると 0 として扱われる |
基本的な使い方
JavaScript
const str = 'Hello, World!';
// 文字列が見つかった場合 → 開始位置のインデックスを返す
console.log(str.indexOf('World')); // 7
console.log(str.indexOf('Hello')); // 0
console.log(str.indexOf('o')); // 4(最初に見つかった位置)
// 文字列が見つからない場合 → -1 を返す
console.log(str.indexOf('world')); // -1(大文字小文字が区別される)
console.log(str.indexOf('xyz')); // -1
// 空文字列を検索
console.log(str.indexOf('')); // 0
大文字と小文字の区別
indexOf() は大文字と小文字を区別します。大文字小文字を無視して検索したい場合は、あらかじめ文字列を小文字(または大文字)に変換してから比較します。
JavaScript
const str = 'Hello, World!';
// 大文字小文字を区別する
console.log(str.indexOf('world')); // -1(見つからない)
console.log(str.indexOf('World')); // 7(見つかる)
// 大文字小文字を無視して検索する方法
const lowerStr = str.toLowerCase();
console.log(lowerStr.indexOf('world')); // 7(見つかる)
ポイント:大文字小文字を区別しない検索が頻繁に必要な場合は、正規表現の i フラグ(str.search(/world/i))を使う方法もあります。
fromIndex(第2引数)を活用した検索
indexOf() の第2引数 fromIndex を指定すると、その位置から検索を開始します。これを利用すると、同じ文字列の複数の出現位置を取得できます。
途中から検索する
JavaScript
const str = 'abcabc';
// 先頭から検索(デフォルト)
console.log(str.indexOf('abc')); // 0
// インデックス1から検索
console.log(str.indexOf('abc', 1)); // 3
// インデックス4から検索(見つからない)
console.log(str.indexOf('abc', 4)); // -1
注意:fromIndex に負の値を指定すると 0 として扱われます。fromIndex が文字列の長さ以上の場合は検索が行われず、常に -1 を返します。
すべての出現位置を取得するループ
第2引数を活用して、文字列中のすべての出現位置をループで取得できます。
JavaScript
const str = 'JavaScript is great. Java is also great.';
const searchWord = 'great';
const positions = [];
let pos = str.indexOf(searchWord);
while (pos !== -1) {
positions.push(pos);
pos = str.indexOf(searchWord, pos + 1);
}
console.log(positions); // [15, 35]
このパターンは文字列の出現回数カウントにも応用できます(後述の「実務でよく使うパターン」で詳しく解説します)。
Array.prototype.indexOf()
配列にも indexOf() メソッドがあり、配列の中から指定した値を検索して最初に見つかったインデックスを返します。構文は文字列版とほぼ同じです。
基本的な使い方
JavaScript
const fruits = ['apple', 'banana', 'cherry', 'banana'];
// 要素が見つかった場合
console.log(fruits.indexOf('banana')); // 1(最初の位置)
console.log(fruits.indexOf('cherry')); // 2
// 要素が見つからない場合
console.log(fruits.indexOf('grape')); // -1
// fromIndex を指定
console.log(fruits.indexOf('banana', 2)); // 3(インデックス2以降で検索)
厳密等価比較(===)の注意点
Array.prototype.indexOf() は内部で厳密等価比較(===)を使います。そのため、型が異なる値は一致しません。
JavaScript
const arr = [1, 2, 3];
// 数値の 1 は見つかる
console.log(arr.indexOf(1)); // 0
// 文字列の '1' は見つからない(=== で比較するため)
console.log(arr.indexOf('1')); // -1
// オブジェクトの参照も === で比較
const obj = { id: 1 };
const list = [{ id: 1 }, obj];
console.log(list.indexOf({ id: 1 })); // -1(別のオブジェクト)
console.log(list.indexOf(obj)); // 1(同じ参照)
NaN が見つからない問題
indexOf() は === で比較するため、NaN を検索できません。これは NaN === NaN が false になるという JavaScript の仕様に起因します。
JavaScript
const arr = [1, NaN, 3];
// indexOf() では NaN を見つけられない
console.log(arr.indexOf(NaN)); // -1
// includes() なら NaN を検出できる
console.log(arr.includes(NaN)); // true
// findIndex() でも検出可能
console.log(arr.findIndex(v => Number.isNaN(v))); // 1
注意:配列に NaN が含まれる可能性がある場合は、indexOf() ではなく includes() または findIndex() を使いましょう。
includes() との違い
ES2016で追加された includes() は、indexOf() と同じく値の存在を確認するメソッドですが、戻り値や動作に違いがあります。
比較表
| 項目 |
indexOf() |
includes() |
| 戻り値 |
インデックス(数値)または -1 |
true / false(真偽値) |
| NaN の検索 |
検出できない |
検出できる |
| undefined の検索 |
検出できる |
検出できる |
| 位置の取得 |
可能(インデックスを返す) |
不可(true/false のみ) |
| 対応環境 |
ES1(初期から利用可能) |
ES2016(ES7) |
| 主な用途 |
位置を知りたいとき |
存在するかだけ知りたいとき |
コードで比較
JavaScript
const arr = [10, 20, 30];
// indexOf(): 位置を返す
console.log(arr.indexOf(20)); // 1
console.log(arr.indexOf(99)); // -1
// includes(): 真偽値を返す
console.log(arr.includes(20)); // true
console.log(arr.includes(99)); // false
使い分けの指針
indexOf() vs includes() の使い分け
- 「どの位置にあるか」が必要 →
indexOf()
- 「含まれているかどうか」だけ知りたい →
includes()
- NaN の検索が必要 →
includes()
- IE11 対応が必要 →
indexOf()(includes は IE 非対応)
他の検索メソッドとの比較
JavaScriptには indexOf() 以外にもさまざまな検索メソッドがあります。目的に応じて最適なメソッドを選びましょう。
lastIndexOf()
lastIndexOf() は文字列・配列の末尾から検索し、最後に見つかった位置のインデックスを返します。
JavaScript
const str = 'abcabc';
// indexOf(): 先頭から検索 → 最初の位置
console.log(str.indexOf('bc')); // 1
// lastIndexOf(): 末尾から検索 → 最後の位置
console.log(str.lastIndexOf('bc')); // 4
// 配列でも同様
const arr = [1, 2, 3, 2, 1];
console.log(arr.indexOf(2)); // 1
console.log(arr.lastIndexOf(2)); // 3
find() / findIndex()(配列専用)
find() はコールバック関数の条件に一致する最初の要素の値を返し、findIndex() はそのインデックスを返します。オブジェクトの配列検索に特に有用です。
JavaScript
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 3, name: 'Charlie' },
];
// find(): 条件に一致する要素の値を返す
const user = users.find(u => u.id === 2);
console.log(user); // { id: 2, name: 'Bob' }
// findIndex(): 条件に一致する要素のインデックスを返す
const index = users.findIndex(u => u.name === 'Charlie');
console.log(index); // 2
search()(文字列専用・正規表現対応)
search() は文字列メソッドで、正規表現を使った検索が可能です。indexOf() と同様にインデックスを返しますが、fromIndex は指定できません。
JavaScript
const str = 'Hello, World!';
// indexOf(): 文字列のみ
console.log(str.indexOf('World')); // 7
// search(): 正規表現が使える
console.log(str.search(/world/i)); // 7(大文字小文字を無視)
console.log(str.search(/\d+/)); // -1(数字は含まれない)
検索メソッド一覧比較表
| メソッド |
対象 |
戻り値 |
正規表現 |
NaN対応 |
| indexOf() |
文字列 / 配列 |
インデックス or -1 |
不可 |
不可 |
| lastIndexOf() |
文字列 / 配列 |
インデックス or -1 |
不可 |
不可 |
| includes() |
文字列 / 配列 |
true / false |
不可 |
可能 |
| find() |
配列のみ |
要素の値 or undefined |
不可 |
可能 |
| findIndex() |
配列のみ |
インデックス or -1 |
不可 |
可能 |
| search() |
文字列のみ |
インデックス or -1 |
可能 |
– |
実務でよく使うパターン
ここからは、実際の開発現場で indexOf() がどのように使われているかを具体的なコード例で紹介します。
文字列の存在チェック(if文での使い方)
最も基本的なパターンは、indexOf() の戻り値を -1 と比較して、文字列が含まれているかどうかを判定することです。
JavaScript
const message = 'エラーが発生しました: タイムアウト';
// 文字列が含まれているか判定
if (message.indexOf('エラー') !== -1) {
console.log('エラーメッセージを検出しました');
}
// ES2016以降なら includes() がより直感的
if (message.includes('エラー')) {
console.log('エラーメッセージを検出しました');
}
特定の文字列を含む要素のフィルタリング
JavaScript
const files = [
'index.html',
'style.css',
'app.js',
'utils.js',
'README.md',
];
// .js ファイルだけをフィルタリング
const jsFiles = files.filter(file => file.indexOf('.js') !== -1);
console.log(jsFiles); // ['app.js', 'utils.js']
// includes() を使った書き方(推奨)
const jsFiles2 = files.filter(file => file.includes('.js'));
console.log(jsFiles2); // ['app.js', 'utils.js']
URLやファイルパスの判定
JavaScript
const url = 'https://example.com/api/users?page=1';
// HTTPS かどうか判定(先頭一致)
if (url.indexOf('https://') === 0) {
console.log('安全な接続です');
}
// クエリパラメータが含まれているか
if (url.indexOf('?') !== -1) {
const queryStart = url.indexOf('?');
const queryString = url.substring(queryStart + 1);
console.log(queryString); // 'page=1'
}
// ファイルの拡張子を取得
const filename = 'document.pdf';
const dotIndex = filename.lastIndexOf('.');
if (dotIndex !== -1) {
const ext = filename.substring(dotIndex);
console.log(ext); // '.pdf'
}
ポイント:先頭一致の判定には indexOf() === 0 よりも startsWith()(ES2015)を使う方が可読性が高くなります。同様に、末尾一致には endsWith() が便利です。
文字列の出現回数をカウント
JavaScript
function countOccurrences(str, searchWord) {
let count = 0;
let pos = str.indexOf(searchWord);
while (pos !== -1) {
count++;
pos = str.indexOf(searchWord, pos + 1);
}
return count;
}
const text = 'banana';
console.log(countOccurrences(text, 'an')); // 2
const code = 'const a = 1; const b = 2; const c = 3;';
console.log(countOccurrences(code, 'const')); // 3
配列から重複を除外する
JavaScript
const arr = [1, 2, 3, 2, 1, 4, 3];
// indexOf() で重複除外(初回出現のみ残す)
const unique = arr.filter((value, index, self) => {
return self.indexOf(value) === index;
});
console.log(unique); // [1, 2, 3, 4]
// Set を使った方がシンプル(推奨)
const unique2 = [...new Set(arr)];
console.log(unique2); // [1, 2, 3, 4]
実行結果
[1, 2, 3, 4]
[1, 2, 3, 4]
よくあるミスと注意点
indexOf() の使い方を間違えると、意図しないバグが発生します。ここでは特に頻度の高いミスを紹介します。
ミス1: indexOf() の戻り値をそのままif文で使ってしまう
最も多いミスがこれです。indexOf() が 0 を返した場合、「先頭で見つかった」という意味ですが、0 は JavaScript では falsy な値です。
JavaScript
const str = 'Hello, World!';
// NG: 0 は falsy なので、先頭で見つかった場合に false 扱いになる
if (str.indexOf('Hello')) {
console.log('見つかった'); // 実行されない!
}
// OK: -1 と比較する
if (str.indexOf('Hello') !== -1) {
console.log('見つかった'); // 実行される
}
注意:if (str.indexOf(...)) のように書くと、先頭(インデックス0)で見つかった場合に「見つからなかった」と誤判定されます。必ず !== -1 で比較しましょう。
ミス2: indexOf() === 0 と indexOf() !== -1 の混同
この2つは意味がまったく異なります。
| 条件式 |
意味 |
用途 |
indexOf(x) !== -1 |
x がどこかに含まれている |
部分一致の判定 |
indexOf(x) === 0 |
x が先頭にある |
前方一致の判定 |
indexOf(x) === -1 |
x が含まれていない |
不在の判定 |
JavaScript
const url = 'https://example.com';
// 「https:// で始まるか」の判定
console.log(url.indexOf('https://') === 0); // true(先頭一致)
// 「example を含むか」の判定
console.log(url.indexOf('example') !== -1); // true(部分一致)
// ES2015以降はこちらが推奨
console.log(url.startsWith('https://')); // true
console.log(url.includes('example')); // true
ミス3: undefined と null の検索結果
JavaScript
// String.indexOf() に undefined を渡すと 'undefined' 文字列として検索される
const str = 'value is undefined';
console.log(str.indexOf(undefined)); // 9('undefined' という文字列を検索)
console.log(str.indexOf()); // 9(引数省略も undefined 扱い)
// Array.indexOf() では undefined 値そのものを検索
const arr = [1, undefined, 3];
console.log(arr.indexOf(undefined)); // 1
// 疎な配列(sparse array)の場合
const sparse = [1, , 3]; // インデックス1は空スロット
console.log(sparse.indexOf(undefined)); // -1(空スロットは undefined ではない)
注意:String.prototype.indexOf() は引数を文字列に変換してから検索します。undefined は "undefined" として、null は "null" として検索される点に注意してください。
よくある質問(FAQ)
Q. indexOf()とincludes()の違いは何ですか?
A. indexOf()は見つかった位置(インデックス)を返し、見つからない場合は-1を返します。includes()は真偽値を返します。存在確認だけならincludes()の方が意図が明確です。
Q. indexOf()で後ろから検索するには?
A. lastIndexOf()を使います。配列・文字列どちらにも使えます。第2引数で検索開始位置を後ろから指定することもできます。
Q. indexOf()はNaNを見つけられますか?
A. いいえ。NaN === NaNはfalseなのでindexOf(NaN)は-1を返します。NaNを探したい場合はfindIndex(Number.isNaN)を使ってください。
まとめ
indexOf() はJavaScriptの基本的な検索メソッドです。最後に、場面ごとの最適なメソッドの選び方を整理します。
| やりたいこと |
推奨メソッド |
| 文字列が含まれているか確認したい |
includes() |
| 文字列の出現位置を取得したい |
indexOf() |
| 末尾から検索して位置を取得したい |
lastIndexOf() |
| 先頭一致・末尾一致を判定したい |
startsWith() / endsWith() |
| 正規表現で検索したい |
search() / match() |
| 配列から条件に合う要素を探したい |
find() / findIndex() |
| 配列に値が含まれているか確認したい |
includes() |
| NaN を検索したい |
includes() / findIndex() |
覚えておくべき3つのポイント
- 存在チェックだけなら
includes() を使う(可読性が高い)
- 位置が必要なら
indexOf() を使う(戻り値がインデックス)
indexOf() の戻り値を if 文で直接使わない(0 が falsy になるバグに注意)
indexOf() はES1から存在する歴史あるメソッドですが、ES2015以降は includes()・startsWith()・find() など、より目的に特化したメソッドが追加されています。レガシーコードでは indexOf() を多く見かけますが、新規コードでは用途に応じて適切なメソッドを選択しましょう。