String.prototype.indexOf and _.indexOf
Today I was surprised to learn that the behavior for
_.indexOf is not equivalent to
indexOf on Strings.
Before I explain, let’s note that there are two distinct
indexOf functions, one for Strings and one for Arrays. Interestingly, the two have differing browser support for IE —
String.prototype.indexOf has IE6+ support while
Array.prototype.indexOf has IE9+ support.
_.indexOf is for arrays. Note that it is under the “Array” heading and the documentation suggests that it takes an array, not a string. Unfortunately, the intent of _.indexOf is obfuscated when stumbling upon its usage in a codebase.
Of course, this subtlety is more misleading if you were to think “Strings are just arrays of characters!” and not appreciate the differences in implementation of the
indexOf performs substring operations while Array’s cannot.
To illustrate the point, consider the differences between
["a","b","c"].indexOf(["b", "c"]). The former returns
1 and the latter
_.indexOf’s implementation we can walk through what happens when we try to run
_.indexOf("abc", "bc"). Underscore first attempts to delegate to
Array.prototype.indexOf, which fails because
"abc".indexOf === String.prototype.indexOf !=== Array.prototype.indexOf. Next, Underscore.js loops through the string, one character at a time, and compares it and the item.
Finally, we return
_.indexOf actually works for strings iff the item is a single character (e.g.
_.indexOf("abc", "c") returns
Lessons learned: If you use
_.indexOf, please know that it is only intended for usage when
Array.prototype.indexOf on the parameters is appropriate. If you want Array.prototype.indexOf for pre-IE9 browsers and you also have Underscore.js, use
_.indexOf. If you need to do substring operation, use