74

Readability aside, are there any discernable differences (performance perhaps) between using

str.indexOf("src") 

and

str.match(/src/)

I personally prefer match (and regexp) but colleagues seem to go the other way. We were wondering if it mattered ...?

EDIT:

I should have said at the outset that this is for functions that will be doing partial plain-string matching (to pick up identifiers in class attributes for JQuery) rather than full regexp searches with wildcards etc.

class='redBorder DisablesGuiClass-2345-2d73-83hf-8293' 

So it's the difference between:

string.indexOf('DisablesGuiClass-');

and

string.match(/DisablesGuiClass-/)
Denis Howe
  • 2,092
  • 1
  • 23
  • 25
immutabl
  • 6,857
  • 13
  • 45
  • 76
  • 5
    I think `str.indexOf("xyz")` should be compared with `/xyz/.test(str)` – Redu Jun 09 '16 at 05:12
  • 1
    here a benchmark, which compares indexOf, regex and match http://jsben.ch/#/r9hBp – EscapeNetscape Oct 21 '16 at 22:02
  • Actually `String.prototype.indexOf` is more comparable to `String.prototype.search` because both will return the start index of the match. The boolean expression `'foo'.indexOf('bar') !== -1` is better comparable to `/bar/.test('foo')` because both result in a bool value. That said, for simple expressions without groups and anchors the performance should be comparable. `str.match` is wasting doing too much because it returns all the matches and I would advise against using it for comparisons.That said, if you don't have a performance problem chose the one that is more readable. – Torsten Walter Jan 10 '19 at 10:00

9 Answers9

62

RegExp is indeed slower than indexOf (you can see it here), though normally this shouldn't be an issue. With RegExp, you also have to make sure the string is properly escaped, which is an extra thing to think about.

Both of those issues aside, if two tools do exactly what you need them to, why not choose the simpler one?

David Tang
  • 92,262
  • 30
  • 167
  • 149
  • Makes sense to me, henceforth we'll be running with `indexOf` unless additional RegExp functionality is required. Many thanks! PS. That configurable testpage you linked to in your response is cool - is it a publicly available thing or something of your own devising? – immutabl Jan 21 '11 at 11:12
  • 3
    @5arx, jsperf, like jsfiddle, is an indispensable tool for quickly testing ideas out. It's a public site, just go to jsperf.com and create your own tests. – David Tang Jan 21 '11 at 11:15
  • 10
    According to this jsperf test it simple not true that indexOf is always fast: http://stackoverflow.com/a/5296314/981933 – F Lekschas Oct 08 '13 at 07:17
  • 1
    The test to which you refer might be accurate, or might not -- it certainly got the RegExp wrong, which does not inspire confidence. `'[\\?|&]'` should be `[?&]` to match either `?` or `&` -- no need for an `|` operator, nor escaping the `?`. – Lee Goddard Mar 02 '16 at 08:38
  • Just to add historical color: As of the date of this comment, on my machine (2017 MBP w/ Chrome 56.0.2924 on Mac OS X 10.12.3), the test linked to in the answer says that the `indexOf` is 12% slower than the regex match. So, with many things, the right answer is probably: It depends. – davemyron Mar 20 '17 at 21:17
  • I don't think this is a complete result since the OP was talking about matching strings, and in a use-case scenario. Changing the test to search for two different strings in the same OR conditional, match/regexp methods can be incredibly slow compared to indexOf (90%). If you find yourself in a situation where you can make the search pattern more terse in situations like the test (pattern in a single regexp), match is almost more than certainly the better choice since you are also reducing the amount of handler code as well. – DBrown Jan 26 '18 at 03:31
  • The jsperf also recreated the regex in each test case, which slowed down non-regex cases significantly. Check https://jsperf.com/regexp-vs-indexof/52 and see that the regex is ~96% slower in a more real-world case. – Pre101 Oct 31 '18 at 20:03
  • Definitely seems to depend, and may have changed since the last comments were made... This benchmark test shows regex (especially pre-compiled) is faster: http://jsben.ch/Jw5yT – Will P. Jun 12 '19 at 17:55
20

Here all possible ways (relatively) to search for string

// 1. includes (introduced in ES6)

var string = "string to search for substring",
    substring = "sea";
string.includes(substring);

// 2. string.indexOf

var string = "string to search for substring",
    substring = "sea";
string.indexOf(substring) !== -1;

// 3. RegExp: test

var string = "string to search for substring",
    expr = /sea/;  // no quotes here
expr.test(string);

// 4. string.match

var string = "string to search for substring",
    expr = "/sea/";
string.match(expr);

//5. string.search

var string = "string to search for substring",
    expr = "/sea/";
string.search(expr);

Here a src: https://koukia.ca/top-6-ways-to-search-for-a-string-in-javascript-and-performance-benchmarks-ce3e9b81ad31

Benchmarks seem to be twisted specially for es6 includes , read the comments.

In resume:

if you don't need the matches. => Either you need regex and so use test. Otherwise es6 includes or indexOf. Still test vs indexOf are close.

And for includes vs indexOf:

They seem to be the same : https://jsperf.com/array-indexof-vs-includes/4 (if it was different it would be wierd, they mostly perform the same except for the differences that they expose check this)

And for my own benchmark test. here it is http://jsben.ch/fFnA0 You can test it (it's browser dependent) [test multiple time] here how it performed (multiple run indexOf and includes one beat the other, and they are close). So they are the same. [here using the same test platform as the article above].

enter image description here enter image description here

And here for the a long text version (8 times longer) http://jsben.ch/wSBA2

enter image description here

Tested both chrome and firefox, same thing.

Notice jsben.ch doesn't handle memory overflow (or there limits correctly. It doesn't show any message) so result can get wrong if you add more then 8 text duplication (8 work well). But the conclusion is for very big text all three perform the same way. Otherwise for short indexOf and includes are the same and test a little bit slower. or Can be the same as it seemed in chrome (firefox 60 it is slower).

Notice with jsben.ch: don't freak out if you get inconsistant result. Try different time and see if it's consistent or not. Change browser, sometimes they just run totally wrong. Bug or bad handling of memory. Or something.

ex:

enter image description here

Here too my benchmark on jsperf (better details, and handle graphs for multiple browsers)

(top is chrome)

normal text https://jsperf.com/indexof-vs-includes-vs-test-2019
resume: includes and indexOf have same perofrmance. test slower.

enter image description here enter image description here (seem all three perform the same in chrom)

Long text (12 time longer then normal) https://jsperf.com/indexof-vs-includes-vs-test-2019-long-text-str/
resume: All the three perform the same. (chrome and firefox) enter image description here

very short string https://jsperf.com/indexof-vs-includes-vs-test-2019-too-short-string/
resume: includes and indexOf perform the same and test slower.

enter image description here

Note: about the benchmark above. For the very short string version (jsperf) had an big error for chrome. Seeing by my eyes. around 60 sample was run for both indexOf and includes same way (repeated a lot of time). And test a little bit less and so slower. don't be fooled with the wrong graph. It's clear wrong. Same test work ok for firefox, surely it's a bug.

Here the illustration: (the first image was the test on firefox) enter image description here waaaa. Suddenly indexOf became superman. But as i said i did the test, and looked at the number of samples it was around 60. Both indexOf and includes and they performed the same. A bug on jspref. Except for this one (maybe because of a memory restriction related problem) all the rest was consistent, it give more details. And you see how many simple happen in real time.

Final resume

indexOf vs includes => Same performance

test => can be slower for short strings or text. And the same for long texts. And it make sense for the overhead that the regex engine add. In chrome it seemed it doesn't matter at all.

Mohamed Allal
  • 17,920
  • 5
  • 94
  • 97
19

Your comparison may not be entirely fair. indexOf is used with plain strings and is therefore very fast; match takes a regular expression - of course it may be slower in comparison, but if you want to do a regex match, you won't get far with indexOf. On the other hand, regular expression engines can be optimized, and have been improving in performance in the last years.

In your case, where you're looking for a verbatim string, indexOf should be sufficient. There is still one application for regexes, though: If you need to match entire words and want to avoid matching substrings, then regular expressions give you "word boundary anchors". For example:

indexOf('bar')

will find bar three times in bar, fubar, barmy, whereas

match(/\bbar\b/)

will only match bar when it is not part of a longer word.

As you can see in the comments, some comparisons have been done that show that a regex may be faster than indexOf - if it's performance-critical, you may need to profile your code.

Tim Pietzcker
  • 328,213
  • 58
  • 503
  • 561
  • 2
    I thought it a fair question, coming from a Perl background, where an equivalent regex is faster than `indexOf`. – Lee Goddard Mar 02 '16 at 08:39
  • 1
    It's no apples with oranges comparison as a trivial regex can be optimized to be as fast as `indexOf`. I've just run https://jsperf.com/substring-test and it claims that "regex case insensitive" is the fastest and 30% faster than "indexOf", which I refuse to believe. – maaartinus May 29 '17 at 01:45
  • While indexOf would find any of those strings, it will only find the first 'bar' in the string. – PRMan Jun 21 '22 at 15:12
11

If you're trying to search for substring occurrences case-insensitively then match seems to be faster than a combination of indexOf and toLowerCase()

Check here - http://jsperf.com/regexp-vs-indexof/152

Yogesh Mangaj
  • 3,200
  • 6
  • 32
  • 45
  • Can confirm, here's another (working) benchmark: http://jsben.ch/Jw5yT -- Notice, regex wins every time whether pre-compiled or not, even faster than case sensitive index of according to this. – Will P. Jun 12 '19 at 17:48
6

You ask whether str.indexOf('target') or str.match(/target/) should be preferred. As other posters have suggested, the use cases and return types of these methods are different. The first asks "where in str can I first find 'target'?" The second asks "does str match the regex and, if so, what are all of the matches for any associated capture groups?"

The issue is that neither one technically is designed to ask the simpler question "does the string contain the substring?" There is something that is explicitly designed to do so:

var doesStringContainTarget = /target/.test(str);

There are several advantages to using regex.test(string):

  1. It returns a boolean, which is what you care about
  2. It is more performant than str.match(/target/) (and rivals str.indexOf('target'))
  3. If for some reason, str is undefined or null, you'll get false (the desired result) instead of throwing a TypeError
elreimundo
  • 6,186
  • 1
  • 13
  • 6
5

Using indexOf should, in theory, be faster than a regex when you're just searching for some plain text, but you should do some comparative benchmarks yourself if you're concerned about performance.

If you prefer match and it's fast enough for your needs then go for it.

For what it's worth, I agree with your colleagues on this: I'd use indexOf when searching for a plain string, and use match etc only when I need the extra functionality provided by regular expressions.

LukeH
  • 263,068
  • 57
  • 365
  • 409
4

Performance wise indexOf will at the very least be slightly faster than match. It all comes down to the specific implementation. When deciding which to use ask yourself the following question:

Will an integer index suffice or do I need the functionality of a RegExp match result?

ChaosPandion
  • 77,506
  • 18
  • 119
  • 157
3

The return values are different

Aside from the performance implications, which are addressed by other answers, it is important to note that the return values for each method are different; so the methods cannot merely be substituted without also changing your logic.

Return value of .indexOf: integer

The index within the calling String object of the first occurrence of the specified value, starting the search at fromIndex.
Returns -1 if the value is not found.

Return value of .match: array

An Array containing the entire match result and any parentheses-captured matched results.
Returns null if there were no matches.

Because .indexOf returns 0 if the calling string begins with the specified value, a simple truthy test will fail.

For example:

Given this class…

class='DisablesGuiClass-2345-2d73-83hf-8293 redBorder' 

…the return values for each would differ:

//  returns `0`, evaluates to `false`
if (string.indexOf('DisablesGuiClass-')) {
    … // this block is skipped.
}

vs.

//  returns `["DisablesGuiClass-"]`, evaluates to `true`
if (string.match(/DisablesGuiClass-/)) { 
    … // this block is run.
}

The correct way to run a truthy test with the return from .indexOf is to test against -1:

if (string.indexOf('DisablesGuiClass-') !== -1) {
//  ^returns `0`                        ^evaluates to `true`
    … // this block is run.
}
Community
  • 1
  • 1
gfullam
  • 11,531
  • 5
  • 50
  • 64
-1

remember Internet Explorer 8 doesnt understand indexOf. But if nobody of your users uses ie8 (google analytics would tell you) than omit this answer. possible solution to fix ie8: How to fix Array indexOf() in JavaScript for Internet Explorer browsers

Community
  • 1
  • 1
NoWomenNoCry
  • 157
  • 1
  • 7