2016-02-01 9 views
8

Dodałem następujące PolyFill do Array na początku mojego projektu:Dodawanie funkcji do Array.prototype w IE skutkuje tym pchane w każdej tablicy jako element

if (!Array.prototype.find) { 
    Array.prototype.find = function(predicate) { 
    if (this === null) { 
     throw new TypeError('Array.prototype.find called on null or undefined'); 
    } 
    if (typeof predicate !== 'function') { 
     throw new TypeError('predicate must be a function'); 
    } 
    var list = Object(this); 
    var length = list.length >>> 0; 
    var thisArg = arguments[1]; 
    var value; 

    for (var i = 0; i < length; i++) { 
     value = list[i]; 
     if (predicate.call(thisArg, value, i, list)) { 
     return value; 
     } 
    } 
    return undefined; 
    }; 
} 

To działa perfekcyjnie w Chrome i Firefox, Internet Explorer, ale na 11, funkcja ta jest rzeczywiście pchnął w każdym Array jako element niego i mogę nawet uzyskać dostęp to lubią:

var a = []; 
a[0](); 

to throwin g wszelkiego rodzaju wyjątki w IE z funkcjami takimi jak .forEach, gdzie spodziewam się pewnych danych i ta funkcja zostanie znaleziona.

Oto zrzut ekranu z narzędzi IE deweloperskich, w tym przypadku, ta tablica powinna mieć tylko 2 elementy, zamiast 3.

IE - wrong

I tak powinno być, z Chrome. W rzeczywistości uważam, że nawet rzeczywista zawartość jest błędna, ale jeszcze się tam nie dostałem (powinna to być tablica zawierająca tablice o długości 2).

Chrome - correct

Jak JavaScript nadal zachowują się tak źle w IE11 i jak mogę poprawnie dodać tę funkcję do prototype zamiast w każdym Array przykład?

Odpowiedz

16

To nie jest "wepchnięte" w każdą tablicę; dodałeś właściwość do prototypowego obiektu, więc w każdej instancji tablicy jest onawidoczna jako i . Tak powinny działać właściwości prototypowe.

To działa w Chrome i Firefox .find() na prototypie w tych środowiskach jest określona w taki sposób, aby były widoczneale nieprzeliczalny. Można to zrobić w IE za pomocą Object.defineProperty():

if (!Array.prototype.find) { 
    Object.defineProperty(Array.prototype, "find", { 
    value: function(predicate) { 
     if (this === null) { 
     throw new TypeError('Array.prototype.find called on null or undefined'); 
     } 
     if (typeof predicate !== 'function') { 
     throw new TypeError('predicate must be a function'); 
     } 
     var list = Object(this); 
     var length = list.length >>> 0; 
     var thisArg = arguments[1]; 
     var value; 

     for (var i = 0; i < length; i++) { 
     value = list[i]; 
     if (predicate.call(thisArg, value, i, list)) { 
      return value; 
     } 
     } 
     return undefined; 
    } 
    }); 
} 

Oprócz własności „wartości”, który jest wyraźnie wartość nowej nieruchomości, właściwości „przeliczalny” i „konfigurowalny” domyślnie false. Oznacza to, że "find" nie pojawi się w żadnej sytuacji, która wymaga iteracji poprzez właściwości obiektu.

+0

To wspaniała odpowiedź i działa! Ostatnie pytanie: wziąłem tę polyfill z Mozilla Developer's Network (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find#Polyfill) i wszystkie ich polyfills używają to samo podejście do bezpośredniego dodawania funkcji do prototypu obiektu (inny przykład: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith#Polyfill). Czy powinienem go całkowicie unikać i zawsze używać 'defineProperty'? Czy to będzie tylko problem w 'Array'? –

+1

Osobiście użyłbym 'defineProperty()', ale jeśli próbujesz sprawić, żeby rzeczy działały na IE8 lub starszym, napotkasz trudności. Zawsze możesz wrócić do zwykłego dodawania właściwości do prototypu, jeśli 'defineProperty' nie działa. – Pointy

+0

@WillP. tak, przed IE9 natywne prototypy w IE nie mogły być modyfikowane. – Pointy