String.prototype.includes()
Exists purely for readability. It answers the question you actually asked, instead of making you compare an index against -1 and hope you got the operator right.
Demo
A match anywhere counts, including in the middle of a word — 'ell' is found inside 'hello', which matters when testing against user input where a word boundary was intended. The comparison is case sensitive and does no normalisation whatsoever, so 'HELLO' is simply absent from 'hello'. The last case surprises people: an empty string is considered present in every string, including the empty string itself, because it trivially occurs at position 0.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| searchString | string | yes | The text to look for. A RegExp here is a TypeError — this method is for literal text only. |
| position | number | no (0) | Index to start searching from. Anything before it is ignored entirely. |
Return value
boolean — True if the search string occurs anywhere at or after position. Always a boolean — never an index.
Common patterns
const found = s.toLowerCase().includes(needle.toLowerCase());
const hits = items.filter(i => i.name.toLowerCase().includes(term));
const isImage = EXTS.some(e => name.endsWith(e));
Examples
Pitfalls
'Hello'.includes('hello')
'Hello'.toLowerCase().includes('hello')
''.includes('')
const found = needle !== "" && s.includes(needle);
'abc'.includes(/b/)
/b/.test('abc')
'non-admin'.includes('admin')
roles.split(',').includes('admin')
When to use
- Testing whether text contains a fragment
- Search-box filtering, with both sides lowercased
- Anywhere indexOf was only ever compared against -1
- You need the position → indexOf
- You need a pattern → RegExp.test or search
- You are checking the start or end → startsWith, endsWith
- You are checking membership in a list → split then Array.includes
Notes
FAQ
Lowercase both operands. For text with accents that is still not enough — normalising and stripping combining marks handles é versus e, and localeCompare with sensitivity options is the thorough answer.
s.toLowerCase().includes(t.toLowerCase()); // accent-insensitive: s.normalize('NFD').replace(/\p{Diacritic}/gu, '')