Cara memperbaiki Array indexOf () di JavaScript untuk browser Internet Explorer

295

Jika Anda telah bekerja dengan JavaScript, Anda tahu bahwa Internet Explorer tidak mengimplementasikan fungsi ECMAScript untuk Array.prototype.indexOf () [termasuk Internet Explorer 8]. Ini bukan masalah besar, karena Anda dapat memperluas fungsionalitas pada halaman Anda dengan kode berikut.

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

Kapan saya harus menerapkan ini?

Haruskah saya membungkusnya di semua halaman saya dengan cek berikut, yang memeriksa apakah fungsi prototipe ada dan jika tidak, silakan dan memperpanjang prototipe Array?

if (!Array.prototype.indexOf) {

    // Implement function here

}

Atau apakah browser memeriksa dan apakah itu Internet Explorer maka cukup laksanakan?

//Pseudo-code

if (browser == IE Style Browser) {

     // Implement function here

}
Bobby Borszich
sumber
Sebenarnya Array.prototype.indexOfbukan bagian dari ECMA-262 / ECMAScript. Lihat ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf Mungkin Anda berpikir String.prototype.indexOf...
Crescent Fresh
5
Ini adalah ekstensi, bukan bagian dari standar asli. Namun, itu harus diimplementasikan sebagai bagian dari Javascript 1.6 (yang gagal dilakukan IE) developer.mozilla.org/en/New_in_JavaScript_1.6
Josh Stodola
1
@Josh: hanya merujuk pada "IE tidak mengimplementasikan fungsi ECMAScript ..."
Crescent Fresh
4
Implementasi Anda Array.indexOftidak memperhitungkan indeks awal yang negatif. Lihat penerapan stop-gap saran Mozilla di sini: developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…
nickf
3
Saya telah memperbarui pertanyaan untuk menggunakan "===", karena saya khawatir orang akan menyalinnya dengan "==" dan itu akan salah - selain itu tidak masalah. Lihat jawaban Eli Grey.
joshcomley

Jawaban:

213

Lakukan seperti ini...

if (!Array.prototype.indexOf) {

}

Sebagai kompatibilitas yang disarankan oleh MDC .

Secara umum, kode deteksi peramban adalah yang besar tidak boleh tidak.

Josh Stodola
sumber
Saya tidak memiliki cukup perwakilan untuk mengedit pertanyaan tetapi merasa bebas untuk menghapus istilah ECMAScript dan menggantinya dengan kata-kata yang sesuai. Terima kasih lagi
Bobby Borszich
12
Hati-hati jika Anda menggunakan deteksi semacam ini. Pustaka lain mungkin mengimplementasikan fungsi ini sebelum Anda mengujinya, dan itu mungkin tidak sesuai standar (prototipe telah melakukannya beberapa waktu yang lalu). Jika saya bekerja di lingkungan yang bermusuhan (banyak coder lain menggunakan banyak perpustakaan yang berbeda), saya tidak akan mempercayai semua ini ...
Pablo Cabrera
Kolom "Tertaut" ---> sangat berguna! Saya suka jawabannya di sini: stackoverflow.com/questions/1744310/…
gordon
Apakah harus dibungkus dengan setiap file js?
rd22
Siapa sebenarnya MDC?
Ferrybig
141

Atau, Anda bisa menggunakan fungsi jQuery 1.2 inArray , yang seharusnya berfungsi di seluruh browser:

jQuery.inArray( value, array [, fromIndex ] )
Moses Lee
sumber
The 'indexOf' adalah kode asli (kanan), jadi jQuery 'inArray ()' akan secepat, seperti menggunakan asli saat tersedia dan poly-fill ketika tidak?
Jeach
10
Ok jadi untuk menjawab komentar saya sendiri (di atas), saya baru mengimplementasikannya dan di Chrome itu secepat ketika saya menggunakan 'indexOf ()', tapi di IE 8 itu sangat, sangat lambat ... jadi setidaknya kita tahu yang 'inArray ()' menggunakan asli saat itu bisa.
Jeach
78

Kode lengkapnya adalah sebagai berikut:

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

Untuk jawaban dan kode yang sangat menyeluruh untuk hal ini serta fungsi-fungsi array lainnya, lihat pertanyaan Stack Overflow Memperbaiki fungsi-fungsi JavaScript Array di Internet Explorer (indexOf, forEach, dll . ) .

Luis Perez
sumber
2
terima kasih hanya memiliki semuanya. Saya sering mengunjungi halaman ini setiap kali saya perlu index-platform lintas Dari dalam proyek baru, dan snippet Anda adalah satu-satunya dengan kode lengkap. :) Beberapa detik itu benar-benar bertambah ketika seseorang sering mengunjungi halaman ini.
dylnmc
16

Pustaka underscore.js memiliki fungsi indexOf yang bisa Anda gunakan sebagai gantinya:

_.indexOf([1, 2, 3], 2)
scotta7exander
sumber
4
Jawaban ini menghindari mengacaukan prototipe array , dan mendelegasikan ke indeks asli Jika tersedia. Saya suka itu.
Brad Koch
Tampaknya menjadi cara termudah jika Anda dapat memasukkan garis bawah atau lodash
ChrisRich
10

Anda harus memeriksa apakah itu tidak didefinisikan menggunakan if (!Array.prototype.indexOf).

Juga, implementasi Anda indexOftidak benar. Anda harus menggunakan ===alih-alih ==dalam if (this[i] == obj)pernyataan Anda , jika tidak [4,"5"].indexOf(5)akan sesuai dengan implementasi Anda, yang salah.

Saya sarankan Anda menggunakan implementasinya di MDC .

Eli Gray
sumber
9

Ada solusi resmi 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;
        };
    }
})();
Will V King
sumber
1
Menjadi pedantic tetapi MDN bukan hanya Mozilla. Ini adalah proyek berbasis komunitas yang berisi staf Mozilla tetapi juga sukarelawan, siapa pun dapat bergabung dan berkontribusi.
ste2425
5

Saya akan merekomendasikan ini kepada siapa pun yang mencari fungsionalitas yang hilang:

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

Ini membawa sebagian besar fungsi ecma5 yang hilang ke browser lama :)

Josh Mc
sumber
** Meskipun saya akan perhatikan bahwa saya memiliki masalah di IE7 dengan lib ini.
Josh Mc
2

Ini implementasi saya. Pada dasarnya, tambahkan ini sebelum skrip lain pada halaman. yaitu di master Anda untuk solusi global untuk Internet Explorer 8. Saya juga menambahkan fungsi trim yang tampaknya digunakan dalam banyak kerangka kerja.

<!--[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]-->
Glennweb
sumber
2

ini bekerja untuk saya.

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;
  };
}
Allen Wong
sumber
1

Dengan Underscore.js

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

sri_bb
sumber