300

If you have worked with JavaScript at any length you are aware that Internet Explorer does not implement the ECMAScript function for Array.prototype.indexOf() [including Internet Explorer 8]. It is not a huge problem, because you can extend the functionality on your page with the following code.

Array.prototype.indexOf = function(obj, start) {
 for (var i = (start || 0), j = this.length; i < j; i++) {
 if (this[i] === obj) { return i; }
 }
 return -1;
}

When should I implement this?

Should I wrap it on all my pages with the following check, which checks if the prototype function exists and if not, go ahead and extend the Array prototype?

if (!Array.prototype.indexOf) {
 // Implement function here
}

Or do browser check and if it is Internet Explorer then just implement it?

//Pseudo-code
if (browser == IE Style Browser) {
 // Implement function here
}
Peter Mortensen
31.3k22 gold badges110 silver badges134 bronze badges
asked Nov 16, 2009 at 19:27
6
  • Actually Array.prototype.indexOf is not part of ECMA-262/ECMAScript. See ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf Maybe you're thinking String.prototype.indexOf... Commented Nov 16, 2009 at 19:39
  • 5
    It's an extension, not part of the original standard. It should, however, be implemented as part of Javascript 1.6 (which IE fails to do) developer.mozilla.org/en/New_in_JavaScript_1.6 Commented Nov 16, 2009 at 19:41
  • 1
    @Josh: was just referring to "IE does not implement the ECMAScript function..." Commented Nov 16, 2009 at 19:48
  • 4
    Your implementation of Array.indexOf doesn't take negative starting indices into account. See Mozilla's suggestion stop-gap implementation here: developer.mozilla.org/en/JavaScript/Reference/Global_Objects/… Commented Oct 27, 2010 at 15:44
  • 3
    I've updated the question to use "===", because I'm worried people will copy it with the "==" and that would be wrong - other than that it's fine. See Eli Grey's answer. Commented Apr 15, 2011 at 19:25

10 Answers 10

215

Do it like this...

if (!Array.prototype.indexOf) {
}

As recommended compatibility by MDC.

In general, browser detection code is a big no-no.

answered Nov 16, 2009 at 19:30
Sign up to request clarification or add additional context in comments.

5 Comments

I don't have enough rep to edit the question but feel free to remove the ECMAScript lingo and replace with the appropriate wording. Thanks Again
Be careful if you use this kind of detection. Another library might implement this function before you test it, and it might not be standards compliant (prototype has done it a while ago). If I were working in a hostile environment (lots of other coders using lots of distinct libraries), I wouldn't trust any of these...
The "Linked" column ---> is really handy! I love the answer here: stackoverflow.com/questions/1744310/…
Does it has to be wrapped in every js file?
Who is MDC exactly?
142

Alternatively, you could use the jQuery 1.2 inArray function, which should work across browsers:

jQuery.inArray( value, array [, fromIndex ] )
Cees Timmerman
20.4k11 gold badges99 silver badges138 bronze badges
answered Apr 14, 2011 at 0:07

2 Comments

The 'indexOf' is native code (right), so will the jQuery 'inArray()' be as fast, such as use native when available and poly-fill when not?
Ok so to answer my own comment (above), I just implemented it and on Chrome it's as fast as when I was using 'indexOf()', but in IE 8 it is very, very slow... so at least we know that 'inArray()' uses native when it can.
80

The full code then would be this:

if (!Array.prototype.indexOf) {
 Array.prototype.indexOf = function(obj, start) {
 for (var i = (start || 0), j = this.length; i < j; i++) {
 if (this[i] === obj) { return i; }
 }
 return -1;
 }
}

For a really thorough answer and code to this as well as other array functions check out Stack Overflow question Fixing JavaScript Array functions in Internet Explorer (indexOf, forEach, etc.) .

answered Jan 11, 2012 at 2:35

1 Comment

thank you for just having the full thing. I visit this page frequently whenever I need cross-platform indexOf in a new project, and your snippet is the only one with full code. :) Those few seconds really add up when one frequents this page.
16

The underscore.js library has an indexOf function you can use instead:

_.indexOf([1, 2, 3], 2)
Brad Koch
20.5k21 gold badges114 silver badges141 bronze badges
answered May 3, 2012 at 14:17

2 Comments

This answer avoids messing with the array prototype, and it delegates to the native indexOf when available. I like it.
Seems to be the easiest way if you are able to include underscore or lodash
10

You should check if it's not defined using if (!Array.prototype.indexOf).

Also, your implementation of indexOf is not correct. You must use === instead of == in your if (this[i] == obj) statement, otherwise [4,"5"].indexOf(5) would be 1 according to your implementation, which is incorrect.

I recommend you use the implementation on MDC.

answered Nov 17, 2009 at 0:45

Comments

9

There is Mozilla official solution: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf

(function() {
 /**Array*/
 // Production steps of ECMA-262, Edition 5, 15.4.4.14
 // Reference: http://es5.github.io/#x15.4.4.14
 if (!Array.prototype.indexOf) {
 Array.prototype.indexOf = function(searchElement, fromIndex) {
 var k;
 // 1. Let O be the result of calling ToObject passing
 // the this value as the argument.
 if (null === this || undefined === this) {
 throw new TypeError('"this" is null or not defined');
 }
 var O = Object(this);
 // 2. Let lenValue be the result of calling the Get
 // internal method of O with the argument "length".
 // 3. Let len be ToUint32(lenValue).
 var len = O.length >>> 0;
 // 4. If len is 0, return -1.
 if (len === 0) {
 return -1;
 }
 // 5. If argument fromIndex was passed let n be
 // ToInteger(fromIndex); else let n be 0.
 var n = +fromIndex || 0;
 if (Math.abs(n) === Infinity) {
 n = 0;
 }
 // 6. If n >= len, return -1.
 if (n >= len) {
 return -1;
 }
 // 7. If n >= 0, then Let k be n.
 // 8. Else, n<0, Let k be len - abs(n).
 // If k is less than 0, then let k be 0.
 k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
 // 9. Repeat, while k < len
 while (k < len) {
 // a. Let Pk be ToString(k).
 // This is implicit for LHS operands of the in operator
 // b. Let kPresent be the result of calling the
 // HasProperty internal method of O with argument Pk.
 // This step can be combined with c
 // c. If kPresent is true, then
 // i. Let elementK be the result of calling the Get
 // internal method of O with the argument ToString(k).
 // ii. Let same be the result of applying the
 // Strict Equality Comparison Algorithm to
 // searchElement and elementK.
 // iii. If same is true, return k.
 if (k in O && O[k] === searchElement) {
 return k;
 }
 k++;
 }
 return -1;
 };
 }
})();
answered Mar 12, 2015 at 6:20

1 Comment

Just being pedantic but MDN is not just Mozilla. It is a community driven project that contains Mozilla staff but also volunteers, anyone can join and contribute.
5

I would recommend this to anyone looking for missing functionality:

http://code.google.com/p/ddr-ecma5/

It brings in most of the missing ecma5 functionality to older browers :)

answered Jun 7, 2012 at 23:55

1 Comment

** Although I will note that I have had problems in IE7 with this lib.
2

This was my implementation. Essentially, add this before any other scripts on the page. i.e. in your master for a global solution for Internet Explorer 8. I also added in the trim function which seems to be used in allot of frameworks.

<!--[if lte IE 8]>
<script>
 if (!Array.prototype.indexOf) {
 Array.prototype.indexOf = function(obj, start) {
 for (var i = (start || 0), j = this.length; i < j; i++) {
 if (this[i] === obj) {
 return i;
 }
 }
 return -1;
 };
 }
 if(typeof String.prototype.trim !== 'function') {
 String.prototype.trim = function() {
 return this.replace(/^\s+|\s+$/g, '');
 };
 };
</script>
<![endif]-->
answered Mar 13, 2014 at 5:52

Comments

2

it works for me.

if (!Array.prototype.indexOf) {
 Array.prototype.indexOf = function(elt /*, from*/) {
 var len = this.length >>> 0;
 var from = Number(arguments[1]) || 0;
 from = (from < 0)? Math.ceil(from) : Math.floor(from);
 if (from < 0)
 from += len;
 for (; from < len; from++) {
 if (from in this && this[from] === elt)
 return from;
 }
 return -1;
 };
}
answered Jan 28, 2016 at 6:54

Comments

1

With the Underscore.js

var arr=['a','a1','b'] _.filter(arr, function(a){ return a.indexOf('a') > -1; })

answered Jan 21, 2015 at 12:33

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.