String.prototype.indexOf()
Returns the index of the first occurrence of a substring, or -1 when it is not found.
indexOf(searchString)
indexOf(searchString, position)- Added in JavaScript ECMAScript 1
Parameters
| Parameter | Type | Description |
|---|---|---|
$searchString | string | The substring to search for. All values are coerced to strings, so omitting it searches for the literal text "undefined". |
$positionoptional | number= 0 | The index at or after which the match must start. Values below 0 behave like 0; values above str.length mean the string is not searched at all. |
Return value
numberThe index of the first occurrence of searchString at or after position, or -1 if it is not found.
indexOf() performs a case-sensitive, left-to-right scan and reports where the match starts. Use it when you need the position; if you only need a yes/no answer, includes() says so more clearly.
The -1 trap
A match at the very start returns 0, which is falsy. if (s.indexOf(x)) and if (s.indexOf(x) > 0) are both wrong — the only correct tests are !== -1 and >= 0. This is the single most common bug on this method.
Empty search strings
Searching for "" returns position clamped to the string length: "hello world".indexOf("") is 0, indexOf("", 3) is 3, and indexOf("", 13) is 11. It never returns -1, so an unfiltered empty term always looks like a hit.
Finding every occurrence
Loop with the second argument, restarting from found + 1 (or found + needle.length if overlapping matches should be skipped). Forgetting to advance the offset gives you an infinite loop that finds the same index forever.
Matching is by UTF-16 code unit, so the returned index is a code-unit offset — feed it straight into slice(), not into a per-character count.
Example
When to use it
- Split a header at its first colon without a regex
- Find where a marker starts so you can slice around it
- Collect every position of a repeated token in a document
- Check for a substring in engines too old for includes()
Frequently asked questions
How do I find the position of a substring in JavaScript?
Call str.indexOf(substring); it returns the zero-based index of the first match, or -1 if there is none. Pass a second argument to start searching further along.
Why does indexOf() return 0 instead of true?
It returns a position, not a boolean, and 0 means the match starts at the first character. Compare with !== -1, or use includes() when you only want a boolean.
How do I find all occurrences of a substring?
Loop, passing the previous index plus one as the position argument, until indexOf() returns -1. Advance by the needle's length instead if overlapping matches should be ignored.
More examples
Every occurrence of a substring
Restarting one past each hit walks the whole string. The second line shows overlapping matches: starting at 1 and 2 still finds "aa", which a non-overlapping scan would skip.
const hay = "the rain in spain";
const positions = [];
let i = hay.indexOf("in");
while (i !== -1) {
positions.push(i);
i = hay.indexOf("in", i + 1); // must advance, or this never ends
}
console.log(positions); // [ 6, 9, 15 ]
console.log("aaaa".split("").map((_, n) => "aaaa".indexOf("aa", n)));
// [ 0, 1, 2, -1 ]Testing for presence correctly
Index 0 is a real match but a falsy number, so only the explicit comparisons (or includes()) report it correctly.
const role = "admin:write";
console.log(role.indexOf("admin")); // 0
console.log(Boolean(role.indexOf("admin"))); // false — the bug
console.log(role.indexOf("admin") !== -1); // true
console.log(role.indexOf("admin") >= 0); // true
console.log(role.includes("admin")); // true — no comparison needed
console.log(role.indexOf("admin", 1)); // -1 — position excludes it
Discussion