The position-finding counterpart to indexOf, for patterns instead of literal text. It takes no starting offset and it ignores a regex lastIndex entirely.
String methodES3 (1999)Live demo
Common call
s.search(/\d/)
Returns
an index, or -1
Replaces
match(...).index, with its null check
Watch out
a STRING argument is compiled as a regex — search('.') is not a dot
string.search(regexpregexp — The pattern to find. A non-RegExp argument is passed to the RegExp constructor, so a plain string is interpreted as a PATTERN rather than literal text. Omitted entirely, an empty regex matches at 0.type: RegExp · required)
→ number
Demo
Live evaluation
Try:
Inputs
sstringtext that may contain a digit
Output
'abc123'.search(/\d/)
3
The result is an index, exactly like indexOf, so the same -1 sentinel applies and the same truthiness trap comes with it: a match at position 0 is falsy. The difference from indexOf is that the argument is a PATTERN — here /\d/ finds whichever character happens to be a digit, which no literal-text search could do. What search cannot do is start from an offset; there is no second argument.
Parameters
Name
Type
Required
Description
regexp
RegExp
yes
The pattern to find. A non-RegExp argument is passed to the RegExp constructor, so a plain string is interpreted as a PATTERN rather than literal text. Omitted entirely, an empty regex matches at 0.
Return value
number — The index where the pattern first matches, or -1 if it never does. The same sentinel as indexOf, with the same truthiness hazard.
Common patterns
Find where a pattern starts
Then slice around it.
consti = s.search(/\d/);
constrest = i === -1 ? s : s.slice(i);
Detect a character class
Where the thing you seek is a kind, not a value.
consthasUpper = s.search(/[A-Z]/) !== -1;
Just testing? Use test
Clearer when the position is irrelevant.
if (/[A-Z]/.test(s)) { }
Examples
1. Finds a digit
'abc123'.search(/\d/)
Returns
3
2. No match
'abc'.search(/\d/)
Returns
-1
3. Match at zero
'abc'.search(/a/)
Returns
0
4. A string becomes a regex
'a.c'.search('.')
Returns
0
5. indexOf is literal
'a.c'.indexOf('.')
Returns
1
6. No arguments
'abc'.search()
Returns
0
Pitfalls
1. A string argument is compiled as a regular expression
The worst trap on this method. search(".") does not look for a dot — the string is handed to the RegExp constructor, where a dot means any character, so it matches at position 0. Anything containing regex metacharacters silently searches for the wrong thing.
Dot is a wildcard
'a.c'.search('.')
0
indexOf for literals
'a.c'.indexOf('.')
1
2. A match at position 0 is falsy
Identical to indexOf, and identically dangerous. The -1 failure value is truthy while a successful match at the start is falsy, so a bare if on the result is wrong in both directions.
Backwards
if ('abc'.search(/a/)) { /* neverruns */ }
0 is falsy
Compare explicitly
if ('abc'.search(/a/) !== -1) { }
runs
3. There is no starting position argument
indexOf takes one; search does not. Searching onwards from an offset means slicing first and then adding the offset back, which is easy to get off by one.
No second argument
'hello'.search(/l/, 3)
2 // the 3 is ignored
Slice and re-add
consti = 'hello'.slice(3).search(/l/);
i === -1 ? -1 : i + 3
3
4. It ignores the g flag and lastIndex
Unlike exec and test, search always scans from the beginning and never updates lastIndex. That makes it safe to use with a shared global regex — and means adding /g to it accomplishes nothing at all.
lastIndex ignored
constr = /a/g;
r.lastIndex = 5;
"aaa".search(r)
0
Use exec for stateful scanning
r.exec(s)
respects lastIndex
When to use
Use it
Finding the position of a pattern rather than literal text
Locating the first character of a given class
Replacing a match(...).index that needs a null guard
Reach for something else
The target is literal text → indexOf, which will not reinterpret it
You only need a boolean → RegExp.test
You need the matched text → match or matchAll
You need to search from an offset → indexOf, or slice first
Notes
Complexity
Depends on the pattern; scans from the start every time
Return
A number; nothing is allocated or modified
CPython impl
V8: Builtins-string-search / regexp.cc
Memory
No allocation for the result
Thread-safe
Single-threaded; lastIndex is neither read nor written, so a shared regex is safe here
indexOf for literal text — it is faster and, crucially, it will not reinterpret your argument as a pattern. search only when you genuinely need a regex. The fact that search accepts a string at all is a trap rather than a convenience.