Jak naprawić Array indexOf () w JavaScript dla przeglądarek Internet Explorer


295

Jeśli pracujesz z JavaScriptem na dowolnej długości, wiesz, że Internet Explorer nie implementuje funkcji ECMAScript dla Array.prototype.indexOf () [w tym Internet Explorer 8]. Nie jest to duży problem, ponieważ możesz rozszerzyć funkcjonalność swojej strony o następujący kod.

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

Kiedy powinienem to wdrożyć?

Czy powinienem owinąć go na wszystkich moich stronach następującym sprawdzeniem, które sprawdza, czy funkcja prototypu istnieje, a jeśli nie, śmiało i rozszerzać prototyp Array?

if (!Array.prototype.indexOf) {

    // Implement function here

}

A może przeglądarka sprawdza, a jeśli jest to Internet Explorer, to po prostu go wdrażasz?

//Pseudo-code

if (browser == IE Style Browser) {

     // Implement function here

}

W rzeczywistości Array.prototype.indexOfnie jest częścią ECMA-262 / ECMAScript. Zobacz ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf Może myślisz String.prototype.indexOf...
Crescent Fresh

5
To rozszerzenie, nie będące częścią oryginalnego standardu. Powinien jednak zostać zaimplementowany jako część Javascript 1.6 (czego nie robi IE) developer.mozilla.org/en/New_in_JavaScript_1.6
Josh Stodola

1
@Josh: właśnie odnosił się do „IE nie implementuje funkcji ECMAScript ...”
Crescent Fresh

4
Twoje wdrożenie Array.indexOfnie bierze pod uwagę ujemnych wskaźników początkowych. Zobacz sugestię Mozilli dotyczącą zatrzymania luki tutaj: developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…
nickf

3
Zaktualizowałem pytanie, aby używać „===”, ponieważ obawiam się, że ludzie skopiują je za pomocą „==” i byłoby to złe - poza tym jest w porządku. Zobacz odpowiedź Eli Grey.
joshcomley,

Odpowiedzi:


213

Zrób to tak ...

if (!Array.prototype.indexOf) {

}

Zgodnie z zalecaną kompatybilnością przez MDC .

Ogólnie rzecz biorąc, kod wykrywający w przeglądarce jest dużym nie-nie.


Nie mam wystarczającej liczby przedstawicieli, aby edytować pytanie, ale mogę usunąć żargon ECMAScript i zastąpić go odpowiednim sformułowaniem.
Jeszcze

12
Uważaj, jeśli używasz tego rodzaju wykrywania. Inna biblioteka może zaimplementować tę funkcję przed jej przetestowaniem i może nie być zgodna ze standardami (prototyp zrobił to jakiś czas temu). Gdybym pracował w nieprzyjaznym środowisku (wiele innych programistów korzystających z wielu odrębnych bibliotek), nie ufałbym żadnym z nich ...
Pablo Cabrera,

Kolumna „Połączone” ---> jest naprawdę przydatna! Uwielbiam odpowiedź tutaj: stackoverflow.com/questions/1744310/…
Gordon

Czy musi być zawinięty w każdy plik js?
rd22

Kim dokładnie jest MDC?
Ferrybig

141

Alternatywnie możesz użyć funkcji inArray jQuery 1.2 , która powinna działać w różnych przeglądarkach:

jQuery.inArray( value, array [, fromIndex ] )

„IndexOf” jest rodzimym kodem (po prawej), więc czy jQuery „inArray ()” będzie tak szybkie, jak na przykład użycie natywnego, gdy jest dostępne, i wielokrotnego wypełniania, gdy nie?
Jeach

10
Ok, aby odpowiedzieć na mój komentarz (powyżej), właśnie go zaimplementowałem, a w Chrome jest tak szybki, jak wtedy, gdy korzystałem z „indexOf ()”, ale w IE 8 jest on bardzo, bardzo wolny ... więc przynajmniej wiemy że „inArray ()” używa natywnego, gdy może.
Jeach

78

Pełny kod byłby więc następujący:

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

Aby uzyskać naprawdę dokładną odpowiedź i kod na to, a także inne funkcje tablicowe, sprawdź pytanie Przepełnienie stosu Naprawianie funkcji tablicy JavaScript w Internet Explorerze (indexOf, forEach itp . ) .


2
dziękuję, że masz wszystko. Odwiedzam tę stronę często, gdy potrzebuję wieloplatformowego indeksu w nowym projekcie, a Twój fragment jest jedynym z pełnym kodem. :) Te kilka sekund naprawdę się sumuje, gdy odwiedza się tę stronę.
dylnmc


10

Powinieneś sprawdzić, czy nie jest zdefiniowane za pomocą if (!Array.prototype.indexOf).

Ponadto implementacja indexOfjest niepoprawna. Musisz użyć ===zamiast ==w swoim if (this[i] == obj)oświadczeniu, w przeciwnym razie [4,"5"].indexOf(5)byłoby 1 zgodnie z implementacją, co jest niepoprawne.

Polecam użycie implementacji na MDC .


9

Istnieje oficjalne rozwiązanie Mozilli: 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;
        };
    }
})();

1
Po prostu pedantyczny, ale MDN to nie tylko Mozilla. Jest to projekt kierowany przez społeczność, który zawiera pracowników Mozilli, ale także wolontariuszy, każdy może dołączyć i wnieść swój wkład.
ste2425


2

To była moja realizacja. Zasadniczo dodaj to przed innymi skryptami na stronie. tj. w twoim master dla globalnego rozwiązania dla Internet Explorera 8. Dodałem również funkcję przycinania, która wydaje się być używana w wielu ramach.

<!--[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]-->

2

mi to pasuje.

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

1

Z Underscore.js

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.