What string find does
Finding a substring means asking where a piece of text starts inside a longer string. In JavaScript the main tool is the indexOf() method. You call it on a string and pass the text to look for. It returns a number: the index of the first match, or -1 when the text is not there.
let sentence = "Hello World";
let idx = sentence.indexOf("World");
console.log(idx); // 6
console.log(sentence.indexOf("xyz")); // -1
Indexes start at 0, so "H" is at 0, "e" at 1, and the space at 5. The "W" of "World" is at 6. The returned index is always the position of the first character of the match, not the last.
The three forms
s.indexOf(sub) // index of the first occurrence, or -1
s.lastIndexOf(sub) // index of the last occurrence, or -1
s.indexOf(sub, start) // search starting from index start
When the text appears more than once, the form you pick decides which match you get:
let s = "Hello World";
console.log(s.indexOf("o")); // 4
console.log(s.lastIndexOf("o")); // 7
console.log(s.indexOf("o", 5)); // 7
The first "o" is at index 4, inside "Hello". lastIndexOf scans from the end and finds the one in "World" at index 7. Passing 5 as the second argument to indexOf makes it skip everything before index 5, so it also lands on 7.
Gotchas
Matching is case sensitive
"Hello World".indexOf("hello") is -1, because "h" and "H" are different characters. To ignore case, convert both strings with toLowerCase() first.
-1 is truthy, 0 is falsy
The "not found" value is -1, and in a condition -1 counts as true. Index 0, a match at the very start, counts as false. So this check is wrong:
if (s.indexOf("xyz")) {
console.log("found"); // runs, even though nothing was found
}
Always compare with -1 directly:
if (s.indexOf("xyz") !== -1) {
console.log("found");
}
When you only need a yes or no answer, s.includes("xyz") is clearer and avoids the trap.
Only the first match, unless you loop
To collect every position, search again from just after the previous match:
let t = "banana";
let i = t.indexOf("a");
while (i !== -1) {
console.log(i); // 1, then 3, then 5
i = t.indexOf("a", i + 1);
}
The empty string and out-of-range starts
s.indexOf("") is 0, since the empty string matches at the start. A start index below 0 is treated as 0, and a start beyond the end of the string just gives -1 for any non-empty text.
The exercise, step by step
The starter code gives one variable:
let sentence = "Hello World";
The task is to find where "World" starts. That takes a single new line.
- Declare
idxbelowsentence, withlet. - Call
indexOfonsentenceand pass"World". The method returns6, and that number is stored inidx.
The solution in JavaScript
let sentence = "Hello World";
let idx = sentence.indexOf("World");
You can check the result with console.log(idx), which prints 6. The method never changes sentence. Strings in JavaScript are immutable, so every string method gives you a result and leaves the original alone.
Using the index
An index is most useful together with other string tools. slice cuts a string from a position, so you can take everything from the match onward:
console.log(sentence.slice(idx)); // World
Common mistakes
The first mistake is forgetting that an index counts characters from zero. In "Hello World" the word "World" starts at 6 even though it is the second word, and the string has 11 characters, so the last index is 10. The match ends at idx + "World".length, which is 11, the position just after the final letter.
The second mistake is feeding -1 into other code without checking. For example, url.slice(url.indexOf("/")) looks harmless, but if there is no slash the index is -1, and slice(-1) means "the last character". The program doesn't crash. It quietly returns the wrong answer. Check for -1 before using the index.
The third mistake is confusing overlapping matches. In "aaa", indexOf("aa") is 0 and lastIndexOf("aa") is 1. The two matches overlap, and each method simply reports the one nearest its own end of the string.
Using the index to take a string apart
Once you know where a separator is, you can cut the string around it with slice. For an address like "ann@example.org", find the "@" and take the text on each side:
const email = "ann@example.org";
const at = email.indexOf("@");
console.log(email.slice(0, at)); // ann
console.log(email.slice(at + 1)); // example.org
The first slice stops just before the match, and the second starts one position after it, to skip the "@" itself. This pattern comes up constantly when you process text, and it all starts with indexOf.
Key takeaways
indexOf(sub)returns the index of the first character of the first match, or-1.lastIndexOf(sub)finds the last match, andindexOf(sub, start)begins at a position you choose.- The search is case sensitive.
- Compare the result with
-1. Never use it directly as a condition, because-1is truthy and0is falsy. - Use
includeswhen you only need to know whether the text is present.