294

The below function works fine on Opera, Firefox and Chrome. However, in IE8 it fails on the if ( allowed.indexOf(ext[1]) == -1) part.

Does anyone know why? Is there any obvious mistake?

function CheckMe() {
    var allowed = new Array('docx','xls','xlsx', 'mp3', 'mp4', '3gp', 'sis', 'sisx', 'mp3', 'wav', 'mid', 'amr', 'jpg', 'gif', 'png', 'jpeg', 'txt', 'pdf', 'doc', 'rtf', 'thm', 'rar', 'zip', 'htm', 'html', 'css', 'swf', 'jar', 'nth', 'aac', 'cab', 'wgz');
    var fileinput=document.getElementById('f');
    var ext = fileinput.value.toLowerCase().split('.');
    if ( allowed.indexOf(ext[1]) == -1) 
    {
        document.getElementById('uploadsec').innerHTML = document.getElementById('uploadsec').innerHTML;
        alert('This file type is not allowed!');
    }
}
reformed
  • 4,505
  • 11
  • 62
  • 88
nLL
  • 5,662
  • 11
  • 52
  • 87

7 Answers7

488

Versions of IE before IE9 don't have an .indexOf() function for Array, to define the exact spec version, run this before trying to use it:

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;
  };
}

This is the version from MDN, used in Firefox/SpiderMonkey. In other cases such as IE, it'll add .indexOf() in the case it's missing... basically IE8 or below at this point.

Gras Double
  • 15,901
  • 8
  • 56
  • 54
Nick Craver
  • 623,446
  • 136
  • 1,297
  • 1,155
  • Ah OK, I didn't spot the links. – Tim Down Sep 02 '10 at 17:24
  • 2
    Note the caveat that if you (or libraries you use) use the for/in syntax to enumerate arrays (ex. for(idx in arrayname)stmt;) that this method will be enumerated as well. This is because built-in properties are not enumerated by for/in but user-defined ones are. – Spain Train Nov 03 '10 at 21:03
  • 5
    @Mike - That's a different problem...you shouldn't be using a `for...in` loop to *iterate* an array, it should be used for *enumeration* only. – Nick Craver Nov 03 '10 at 21:05
  • It is a related problem. Enumeration is the listing of elements in a set. Iteration, with an array index as the mutable state, is a common method of enumeration. When available, so is for/in. It is a peculiarity of the ECMA specification that these two methods yield different enumerations of the (seemingly) same set under certain conditions. It is thus convention to use iteration to find the enumeration that excludes unwanted elements, such as functions. This convention is noteworthy for those using the above answer because previously working code that did not follow convention may fail. – Spain Train Nov 05 '10 at 21:16
  • 3
    @Mike - You iterate over an array for more reasons for that..like getting your results in the right order across browsers. Using `for..in` on an array will only cause issues, it's not just a convention..it's unintended usage and an incorrect one. The order and keys are both not completely specified, they're implementation dependent...for example IE will *enumerate* the array items in the order they were *added*, not by their index. However you can *iterate* correctly, accessing by index. – Nick Craver Nov 05 '10 at 21:22
  • 1
    And that illustrates the difference between enumerating the elements and using an index to iterate. Which is why we have both concepts. You can enumerate the values in a linked list, or you can crawl the linked list and return the values from one to the next. One is a mathematical concept, one is a procedural instruction. – jcolebrand Nov 05 '10 at 21:28
  • Using `for ... in` on an array object is just asking for trouble, and virtually 100% of the times I've seen it done (here on SO and elsewhere) it was being done by somebody who didn't know any better, and not by someone with deep understanding of the actual semantics. – Pointy Nov 05 '10 at 21:30
  • 1
    @Pointy Yes! And since many searching for "Why doesn't indexOf work on an array IE8?" may be at a lower sophistication level WRT to js, it may be helpful to point this out as a corollary to the answer. If everyone already had a deep understanding of the spec and differences between implementations, threads such as these wouldn't exist. @Nick You make strong assumptions about correctness. There are many operations for which order does not matter (e.g., set difference.) Also, the original comment made no mention of enumerating in index sequence, just that for/in includes user def fn's. – Spain Train Nov 05 '10 at 23:44
153

If you're using jQuery, you can use $.inArray() instead.

Cymen
  • 14,079
  • 4
  • 52
  • 72
tiegz
  • 1,628
  • 1
  • 10
  • 8
  • 7
    I agree that this is more useful. That is one of the main reasons for using JQuery - it does a lot to alleviate cross browser incompatibilities. – cw24 May 07 '14 at 16:45
17

If you're using jQuery and want to keep using indexOf without worrying about compatibility issues, you can do this :

if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function(val) {
        return jQuery.inArray(val, this);
    };
}

This is helpful when you want to keep using indexOf but provide a fallback when it's not available.

Jed Fox
  • 2,979
  • 5
  • 28
  • 38
Mehdiway
  • 10,337
  • 8
  • 36
  • 68
  • Yes, probably because he didn't include jQuery ¯\_(ツ)_/¯ It is valid syntax. –  Feb 25 '18 at 16:05
10

For a really thorough explanation and workaround, not only for indexOf but other array functions missing in IE check out the StackOverflow question Fixing JavaScript Array functions in Internet Explorer (indexOf, forEach, etc.)

Community
  • 1
  • 1
Luis Perez
  • 27,650
  • 10
  • 79
  • 80
5

Please careful with $.inArray if you want to use it. I just found out that the $.inArray is only works with "Array", not with String. That's why this function will not working in IE8!

The jQuery API make confusion

The $.inArray() method is similar to JavaScript's native .indexOf() method in that it returns -1 when it doesn't find a match. If the first element within the array matches value, $.inArray() returns 0

--> They shouldn't say it "Similar". Since indexOf support "String" also!

ptgamr
  • 584
  • 7
  • 13
  • 16
    It's called `inArray`. That seems pretty definitively to apply to arrays only. That's why it's "similar to" and not "identical to." – tandrewnichols May 22 '14 at 18:28
  • Good note. The funny fact is `indexOf` in a String object is fully found in IE while `indexOf` in Array prototype is not found in IE <= 8. – adi518 Jun 10 '16 at 18:29
  • You're binding it to the array prototype so its not going to affect strings. – kagronick Jun 28 '16 at 14:58
3

The problem

IE<=8 simply doesn't have an indexOf() method for arrays.


The solution

If you need indexOf in IE<=8, you should consider using the following polyfill, which is recommended at the MDN :

if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function(searchElement, fromIndex) {
        var k;
        if (this == null) {
            throw new TypeError('"this" is null or not defined');
        }
        var o = Object(this);
        var len = o.length >>> 0;
        if (len === 0) {
            return -1;
        }
        var n = +fromIndex || 0;
        if (Math.abs(n) === Infinity) {
            n = 0;
        }
        if (n >= len) {
            return -1;
        }
        k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
        while (k < len) {
            if (k in o && o[k] === searchElement) {
                return k;
            }
            k++;
        }
        return -1;
    };
}

Minified :

Array.prototype.indexOf||(Array.prototype.indexOf=function(r,t){var n;if(null==this)throw new TypeError('"this" is null or not defined');var e=Object(this),i=e.length>>>0;if(0===i)return-1;var a=+t||0;if(Math.abs(a)===1/0&&(a=0),a>=i)return-1;for(n=Math.max(a>=0?a:i-Math.abs(a),0);i>n;){if(n in e&&e[n]===r)return n;n++}return-1});
Community
  • 1
  • 1
John Slegers
  • 45,213
  • 22
  • 199
  • 169
1

You can use this to replace the function if it doesn't exist:

<script>
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;
    };
}
</script>
Robert Cadmire
  • 190
  • 1
  • 8