Dlaczego indexOf nie działa na tablicy IE8?

294

Poniższa funkcja działa dobrze w Opera, Firefox i Chrome. Jednak w IE8 zawodzi z if ( allowed.indexOf(ext[1]) == -1)części.

Czy ktoś wie dlaczego? Czy jest jakaś oczywista pomyłka?

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!');
    }
}
nLL
źródło
5
Świetne pytanie, świetna odpowiedź. Dzięki, że dałeś mi dokładnie to, czego potrzebowałem.
Hardwareguy,

Odpowiedzi:

488

Wersje IE przed IE9 nie mają .indexOf()funkcji dla Array, aby zdefiniować dokładną wersję specyfikacji , uruchom ją przed próbą użycia:

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

To jest wersja z MDN , używana w Firefox / SpiderMonkey. W innych przypadkach, takich jak IE, doda .indexOf()w przypadku jego braku ... w zasadzie IE8 lub poniżej w tym momencie.

Nick Craver
źródło
2
Zwróć uwagę na zastrzeżenie, że jeśli ty (lub biblioteki, których używasz) używasz składni for / in, aby wyliczyć tablice (np. Dla (idx w arrayname) stmt;), ta metoda również zostanie wyliczona. Wynika to z faktu, że wbudowane właściwości nie są wyliczane przez for / in, ale są to właściwości zdefiniowane przez użytkownika.
Hiszpania Pociąg
5
@Mike - To inny problem ... nie powinieneś używać for...inpętli do iteracji tablicy, powinna być używana tylko do wyliczenia .
Nick Craver
3
@ Mike - wykonujesz iterację po tablicy z wielu innych powodów. Na przykład uzyskanie wyników we właściwej kolejności w różnych przeglądarkach. Używanie for..inna tablicy spowoduje tylko problemy, to nie tylko konwencja ... to niezamierzone użycie i nieprawidłowe. Zarówno kolejność, jak i klucze nie są w pełni określone, zależą one od implementacji ... na przykład IE wyliczy elementy tablicy w kolejności, w jakiej zostały dodane , a nie według ich indeksu. Można jednak iterować poprawnie, uzyskując dostęp według indeksu.
Nick Craver
1
To ilustruje różnicę między wyliczaniem elementów a użyciem iteracji indeksu. Dlatego mamy oba pojęcia. Możesz wyliczyć wartości na połączonej liście lub przeszukiwać połączoną listę i zwracać wartości od jednej do drugiej. Jedna jest pojęciem matematycznym, druga jest instrukcją proceduralną.
jcolebrand,
1
@Pointy Tak! A ponieważ wielu szuka „Dlaczego indexOf nie działa na tablicy IE8?” może być na niższym poziomie zaawansowania WRT dla js, pomocne może być wskazanie tego jako następstwa odpowiedzi. Gdyby wszyscy mieli już głębokie zrozumienie specyfikacji i różnic między implementacjami, takie wątki nie istniałyby. @Nick Robisz silne założenia dotyczące poprawności. Istnieje wiele operacji, dla których kolejność nie ma znaczenia (np. Ustawianie różnicy). Również w oryginalnym komentarzu nie wspomniano o wyliczaniu w sekwencji indeksu, tylko że dla / in obejmuje definicje użytkownika.
Pociąg Hiszpanii
152

Jeśli używasz jQuery, możesz zamiast tego użyć $ .inArray () .

Tiegz
źródło
7
Zgadzam się, że jest to bardziej przydatne. Jest to jeden z głównych powodów korzystania z JQuery - robi wiele, aby złagodzić niezgodności między przeglądarkami.
cw24
17

Jeśli używasz jQuery i chcesz nadal używać indexOf bez obaw o problemy ze zgodnością, możesz to zrobić:

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

Jest to przydatne, gdy chcesz nadal używać, indexOfale zapewnia rezerwę, gdy nie jest dostępna.

Mehdiway
źródło
Tak, prawdopodobnie dlatego, że nie uwzględnił jQuery ¯_ (ツ) _ / ¯ Jest to poprawna składnia.
5

Ostrożnie z $ .inArray, jeśli chcesz go użyć. Właśnie odkryłem, że $ .inArray działa tylko z „Array”, a nie z String. Dlatego ta funkcja nie działa w IE8!

Interfejs API jQuery wprowadza zamieszanie

Metoda $ .inArray () jest podobna do rodzimej metody JavaScript .indexOf (), ponieważ zwraca -1, gdy nie znajdzie dopasowania. Jeśli pierwszy element w tablicy odpowiada wartości, $ .inArray () zwraca 0

-> Nie powinni mówić „Podobne”. Ponieważ indexOf obsługuje również „String”!

ptgamr
źródło
16
To się nazywa inArray. To wydaje się dość definitywnie dotyczyć tylko tablic. Dlatego jest „podobny do”, a nie „identyczny z”.
tandrewnichols
Dobra notatka Zabawny jest fakt, indexOfże obiekt String został w pełni znaleziony w IE, podczas gdy indexOfw Array nie znaleziono prototypu w IE <= 8.
adi518
Wiążesz go z prototypem tablicy, aby nie wpływał na łańcuchy.
kagronick
3

Problem

IE <= 8 po prostu nie ma indexOf()metody tablic.


Rozwiązanie

Jeśli potrzebujesz indexOfw IE <= 8, powinieneś rozważyć użycie następującego wypełnienia , które jest zalecane w 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;
    };
}

Zminimalizowane:

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});
John Slegers
źródło
1

Możesz użyć tego do zastąpienia funkcji, jeśli ona nie istnieje:

<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
źródło