Memperbaiki fungsi JavaScript Array di Internet Explorer (indexOf, forEach, dll.) [Ditutup]

137

Seperti yang dijelaskan di tempat lain , dan sebaliknya rupanya terkenal, Internet Explorer (pasti versi 7, dan dalam beberapa kasus, versi 8) tidak melaksanakan fungsi utama, khususnya pada Array(seperti forEach, indexOf, dll).

Ada sejumlah solusi di sana-sini, tetapi saya ingin melipat rangkaian penerapan kanonis yang sesuai ke dalam situs kami daripada menyalin dan menempel atau meretas penerapan kami sendiri. Saya telah menemukan js-methods , yang terlihat menjanjikan, tetapi saya pikir saya akan memposting di sini untuk melihat apakah perpustakaan lain lebih direkomendasikan. Beberapa kriteria lain-lain:

  • Library seharusnya menjadi no-operation untuk fungsi-fungsi yang sudah diimplementasikan oleh browser ( js-methodstampaknya berfungsi dengan baik di sini).
  • Mohon non- GPL , meskipun LGPL dapat diterima.
cemerick
sumber

Jawaban:

220

Banyak yang menggunakan implementasi fallback MDC (mis. Untuk indexOf ). Mereka umumnya sangat sesuai dengan standar, bahkan sejauh secara eksplisit memeriksa jenis dari semua argumen.

Sayangnya meskipun jelas bahwa penulis menganggap kode ini sepele dan dapat digunakan secara bebas, tampaknya tidak ada pemberian lisensi eksplisit untuk menuliskannya. Wiki secara keseluruhan adalah CC Attribution-ShareAlike, jika itu adalah lisensi yang dapat diterima (meskipun CC tidak dirancang untuk kode seperti itu).

js-methods terlihat OK secara umum, tetapi tidak sesuai dengan standar di sekitar tepi bagaimana fungsi seharusnya (mis. item daftar yang tidak ditentukan, fungsi yang mengubah daftar). Ini juga penuh dengan metode non-standar acak lainnya, termasuk beberapa yang dipertanyakan seperti stripTag yang cerdik dan codec UTF-8 yang tidak lengkap (yang juga sedikit tidak perlu mengingat unescape(encodeURIComponent)triknya).

Untuk apa nilainya, inilah yang saya gunakan (yang dengan ini saya rilis ke domain publik, jika dapat dikatakan memiliki hak cipta sama sekali). Ini sedikit lebih pendek daripada versi MDC karena tidak mencoba mengetik-sniff bahwa Anda belum melakukan sesuatu yang konyol seperti meneruskan panggilan balik non-fungsi atau indeks non-integer, tetapi selain itu mencoba untuk memenuhi standar. (Beri tahu saya jika saya melewatkan sesuatu. ;-))

'use strict';

// Add ECMA262-5 method binding if not supported natively
//
if (!('bind' in Function.prototype)) {
    Function.prototype.bind= function(owner) {
        var that= this;
        if (arguments.length<=1) {
            return function() {
                return that.apply(owner, arguments);
            };
        } else {
            var args= Array.prototype.slice.call(arguments, 1);
            return function() {
                return that.apply(owner, arguments.length===0? args : args.concat(Array.prototype.slice.call(arguments)));
            };
        }
    };
}

// Add ECMA262-5 string trim if not supported natively
//
if (!('trim' in String.prototype)) {
    String.prototype.trim= function() {
        return this.replace(/^\s+/, '').replace(/\s+$/, '');
    };
}

// Add ECMA262-5 Array methods if not supported natively
//
if (!('indexOf' in Array.prototype)) {
    Array.prototype.indexOf= function(find, i /*opt*/) {
        if (i===undefined) i= 0;
        if (i<0) i+= this.length;
        if (i<0) i= 0;
        for (var n= this.length; i<n; i++)
            if (i in this && this[i]===find)
                return i;
        return -1;
    };
}
if (!('lastIndexOf' in Array.prototype)) {
    Array.prototype.lastIndexOf= function(find, i /*opt*/) {
        if (i===undefined) i= this.length-1;
        if (i<0) i+= this.length;
        if (i>this.length-1) i= this.length-1;
        for (i++; i-->0;) /* i++ because from-argument is sadly inclusive */
            if (i in this && this[i]===find)
                return i;
        return -1;
    };
}
if (!('forEach' in Array.prototype)) {
    Array.prototype.forEach= function(action, that /*opt*/) {
        for (var i= 0, n= this.length; i<n; i++)
            if (i in this)
                action.call(that, this[i], i, this);
    };
}
if (!('map' in Array.prototype)) {
    Array.prototype.map= function(mapper, that /*opt*/) {
        var other= new Array(this.length);
        for (var i= 0, n= this.length; i<n; i++)
            if (i in this)
                other[i]= mapper.call(that, this[i], i, this);
        return other;
    };
}
if (!('filter' in Array.prototype)) {
    Array.prototype.filter= function(filter, that /*opt*/) {
        var other= [], v;
        for (var i=0, n= this.length; i<n; i++)
            if (i in this && filter.call(that, v= this[i], i, this))
                other.push(v);
        return other;
    };
}
if (!('every' in Array.prototype)) {
    Array.prototype.every= function(tester, that /*opt*/) {
        for (var i= 0, n= this.length; i<n; i++)
            if (i in this && !tester.call(that, this[i], i, this))
                return false;
        return true;
    };
}
if (!('some' in Array.prototype)) {
    Array.prototype.some= function(tester, that /*opt*/) {
        for (var i= 0, n= this.length; i<n; i++)
            if (i in this && tester.call(that, this[i], i, this))
                return true;
        return false;
    };
}

Metode ECMA262-5 lain yang tidak diimplementasikan di sini termasuk Array reduce/ reduceRight, yang JSON dan beberapa Objectmetode baru yang dapat diimplementasikan dengan andal sebagai fungsi JS.

bobince
sumber
5
Terima kasih untuk pointer itu - link lain yang pernah saya lihat di mozdev di mana impls seperti itu mungkin ditemukan sudah basi. FYI, kodenya berlisensi MIT, seperti ditentukan di sini: developer.mozilla.org/Project:Copyrights (hampir sebaik yang Anda bisa dapatkan! :-)
cemerick
1
Menariknya, jika saya mereferensikan file js yang berisi semua impls MDC ECMA262-5 sebelum jquery 1.4.2, jquery rusak - misalnya semua penyeleksi gagal, mengembalikan null. Memindahkan MDC impls setelah jquery mengarah ke perilaku yang diharapkan. Sangat aneh.
cemerick
Itu adalah penasaran! Akan melihat itu (apakah Anda memiliki kasus uji?) ... Saya tidak dapat langsung berpikir mengapa ini mungkin terjadi, meskipun apa yang dilakukan jQuery pada baris 72 tampak mencurigakan.
bobince
4
CATATAN: di sebagian besar browser di mana stub ini diperlukan, jika Anda melakukan "for (index in somearray) {...}", Anda perlu menggunakan somearray.hasOwnProperty (index) sebagai pemeriksaan. Mesin JS IE <= 8 akan menyertakan ekstensi array.prototype di dalamnya. Kode asinkron Google Adwords tidak melakukan ini. Terbaik untuk menggunakan Underscore, atau fungsionalitas pustaka lain yang distandarisasi tentang ini.
Pelacak1
1
Ini adalah implementasi indexOf () tercepat untuk IE 8 yang bisa saya temukan. Terima kasih!
Alex Denysenko
27

Lihatlah Underscore.js .

rfunduk
sumber
2
ES5Shim dan rintisan lainnya (seperti dari MDC) cenderung memiliki konsekuensi lain juga. Sebaiknya gunakan garis bawah atau pustaka lain untuk jenis fungsi ini, yang akan menggunakan metode internal jika tersedia.
Pelacak1
Dengan Underscore.js var arr = ['a', 'a1', 'b'] _.filter (arr, function (a) {return a.indexOf ('a')> -1;})
sri_bb
9

Kris Kowal telah mengumpulkan pustaka kecil yang bertindak sebagai shim untuk fungsi ECMAScript 5 yang mungkin hilang dari implementasi browser. Beberapa fungsi telah direvisi berkali-kali oleh orang lain untuk dioptimalkan untuk kecepatan dan untuk mengatasi bug browser. Fungsi-fungsi tersebut ditulis untuk mengikuti spesifikasi sedekat mungkin.

es5-shim.js dirilis di bawah lisensi MIT, ekstensi Array.prototype ada di dekat bagian atas dan Anda dapat memotong dan menghapus fungsi yang tidak Anda perlukan dengan mudah. Saya juga menyarankan Anda mengecilkan skrip karena komentar membuatnya jauh lebih besar dari yang seharusnya.

Andy E
sumber
1

Dengan 'tidak mengimplementasikan fungsi tombol' yang Anda maksud sebenarnya 'sesuai dengan ECMA 262 edisi ke-3' kan? :)

Metode yang Anda maksud adalah bagian dari edisi ke-5 yang baru - untuk browser yang tidak mendukungnya, Anda dapat menggunakan 'shim' berikut yang memanjang dari 3 ke 5 http://github.com/kriskowal/narwhal- lib / blob / narwhal-lib / lib / global-es5.js .

Sean Kinsey
sumber
1
Itu awal yang baik, tetapi ada beberapa kesalahan dalam implementasi yang tidak diambil dari MDC. misalnya. banyak dari metode array tidak meneruskan argumen yang cukup ke callback-nya, dan tidak berfungsi dengan benar dalam kasus mutasi array dalam fungsi callback.
sejak
Saya akan mengambil apa pun yang saya bisa untuk membuat js menjadi bahasa yang lebih waras / berkemampuan minimal. </snark> :-)
cemerick
1

Skrip tersebut tidak bekerja dengan baik dalam pengujian saya. Saya membuat file dengan fungsi yang sama berdasarkan dokumen MDN .

Terlalu banyak area masalah yang diselesaikan di Internet Explorer 8. Lihat kode di egermano / ie-fix.js .

egermano
sumber
0

Dengan Underscore.js

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

sri_bb
sumber