Come risolvere Array indexOf () in JavaScript per i browser Internet Explorer


295

Se hai lavorato con JavaScript a lungo, sei consapevole che Internet Explorer non implementa la funzione ECMAScript per Array.prototype.indexOf () [incluso Internet Explorer 8]. Non è un grosso problema, perché puoi estendere la funzionalità sulla tua pagina con il seguente codice.

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

Quando dovrei implementarlo?

Devo avvolgerlo su tutte le mie pagine con il seguente controllo, che controlla se esiste la funzione prototipo e, in caso contrario, andare avanti ed estendere il prototipo di array?

if (!Array.prototype.indexOf) {

    // Implement function here

}

Oppure controlla il browser e se è Internet Explorer, implementalo?

//Pseudo-code

if (browser == IE Style Browser) {

     // Implement function here

}

In realtà Array.prototype.indexOfnon fa parte dell'ECMA-262 / ECMAScript. Vedi ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf Forse stai pensando String.prototype.indexOf...
Crescent Fresh,

5
È un'estensione, non fa parte dello standard originale. Dovrebbe, tuttavia, essere implementato come parte di Javascript 1.6 (che IE non riesce a fare) developer.mozilla.org/en/New_in_JavaScript_1.6
Josh Stodola,

1
@Josh: si riferiva solo a "IE non implementa la funzione ECMAScript ..."
Crescent Fresh,

4
L'implementazione di Array.indexOfnon tiene conto degli indici di partenza negativi. Vedi l'implementazione stop-gap dei suggerimenti di Mozilla qui: developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…
nickf

3
Ho aggiornato la domanda per usare "===", perché sono preoccupato che la gente la copi con "==" e che sarebbe sbagliato - a parte questo va bene. Vedi la risposta di Eli Grey.
joshcomley,

Risposte:


213

Fai cosi...

if (!Array.prototype.indexOf) {

}

Come compatibilità consigliata da MDC .

In generale, il codice di rilevamento del browser è un grande no-no.


Non ho abbastanza rappresentante per modificare la domanda, ma mi sento libero di rimuovere il gergo ECMAScript e sostituirlo con la formulazione appropriata. Grazie ancora
Bobby Borszich,

12
Fai attenzione se usi questo tipo di rilevamento. Un'altra libreria potrebbe implementare questa funzione prima di testarla e potrebbe non essere conforme agli standard (il prototipo l'ha già eseguita qualche tempo fa). Se stessi lavorando in un ambiente ostile (molti altri programmatori che usano molte librerie distinte), non mi fiderei di nessuno di questi ...
Pablo Cabrera,

La colonna "Linked" ---> è davvero utile! Adoro la risposta qui: stackoverflow.com/questions/1744310/…
gordon

Deve essere racchiuso in ogni file js?
1616

Chi è esattamente MDC?
Ferrybig,

141

In alternativa, è possibile utilizzare la funzione inArray jQuery 1.2 , che dovrebbe funzionare su tutti i browser:

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

'IndexOf' è un codice nativo (a destra), quindi jQuery 'inArray ()' sarà veloce, come usare nativo quando disponibile e poly-fill quando no?
Jeach

10
Ok, per rispondere al mio commento (sopra), l'ho appena implementato e su Chrome è veloce come quando stavo usando 'indexOf ()', ma in IE 8 è molto, molto lento ... quindi almeno sappiamo che 'inArray ()' usa nativo quando può.
Jeach

78

Il codice completo sarebbe quindi questo:

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

Per una risposta e un codice davvero completi a questo, così come altre funzioni dell'array, consulta la domanda Stack Overflow Correzione delle funzioni dell'array JavaScript in Internet Explorer (indexOf, forEach, ecc . ) .


2
grazie per avere solo tutto. Visito frequentemente questa pagina ogni volta che ho bisogno dell'indice multipiattaforma di un nuovo progetto e il tuo frammento è l'unico con il codice completo. :) Quei pochi secondi si sommano davvero quando si frequenta questa pagina.
dylnmc,


10

Dovresti controllare se non è definito usando if (!Array.prototype.indexOf).

Inoltre, l'implementazione di indexOfnon è corretta. È necessario utilizzare ===anziché ==nella propria if (this[i] == obj)dichiarazione, altrimenti [4,"5"].indexOf(5)sarebbe 1 in base all'implementazione, che non è corretto.

Ti consiglio di utilizzare l'implementazione su MDC .


9

Esiste la soluzione ufficiale di Mozilla: 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
Essere solo pedanti ma MDN non è solo Mozilla. È un progetto guidato dalla comunità che contiene personale di Mozilla ma anche volontari, chiunque può unirsi e contribuire.
ste2425


2

Questa era la mia implementazione. In sostanza, aggiungilo prima di qualsiasi altro script nella pagina. vale a dire nel tuo master per una soluzione globale per Internet Explorer 8. Ho anche aggiunto la funzione trim che sembra essere utilizzata in un sacco di framework.

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

per me funziona.

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

Con Underscore.js

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.