2016-02-01 2 views
8

ich folgende polyfill zu Array am Anfang meines Projekts hinzugefügt haben:eine Funktion Hinzufügen in IE führt es Array.prototype wird jedem Array als Element geschoben in

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

Das funktioniert völlig in Ordnung in Chrome und Firefox, aber im Internet Explorer 11 wird diese Funktion geschoben in jedem Array wird tatsächlich als ein Element davon, und ich kann es auch gerne zugreifen:

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

Dies ist throwin g alle möglichen Ausnahmen im IE mit Funktionen wie .forEach wo ich einige Daten erwarte und diese Funktion gefunden wird.

Hier ist ein Screenshot von IE-Entwickler-Tool, in diesem Fall sollte das Array nur 2 Elemente hat, statt 3.

IE - wrong

Und so sollte es von Chrome sein. Tatsächlich glaube ich, dass sogar der tatsächliche Inhalt falsch ist, aber ich bin noch nicht dort angekommen (es sollte ein Array sein, das Arrays der Länge 2 enthält).

Chrome - correct

Wie kann JavaScript verhalten noch so falsch in IE11, und wie kann ich diese Funktion auf die prototype statt korrekt hinzufügen von in jeder Array Instanz?

Antwort

16

Es wird nicht in jedes Array "geschoben"; Sie haben dem Prototypobjekt eine Eigenschaft hinzugefügt, sodass es in jeder Arrayinstanz sichtbar und Enumerable ist. So sollen prototypische Eigenschaften funktionieren.

Es funktioniert in Chrome und Firefox .find() auf dem Prototyp in diesen Umgebungen so definiert ist als sichtbar aber nichtenumerable zu sein. Sie können, dass in IE tun Object.defineProperty() unter Verwendung:

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

Neben Eigenschaft „Wert“, was eindeutig der Wert der neuen Eigenschaft ist, die Eigenschaften „zählbare“ und „konfigurierbar“ default zu false. Das bedeutet, dass "find" in keiner Situation angezeigt wird, in der die Objekteigenschaften durchlaufen werden.

+0

Das ist eine gute Antwort und es funktioniert! Eine letzte Frage, ich nahm diese Polyfill aus dem Mozilla Developer's Network (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find#Polyfill) und alle ihre Polyfills nutzen die Derselbe Ansatz, bei dem die Funktion direkt zum Prototyp des Objekts hinzugefügt wird (ein anderes Beispiel: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith#Polyfill). Soll ich es komplett vermeiden und immer 'defineProperty' verwenden? Oder wird das nur ein Problem in 'Array' sein? –

+1

Persönlich würde ich 'defineProperty()' verwenden, wenn Sie jedoch versuchen, Dinge auf IE8 oder älter zu arbeiten, werden Sie auf Schwierigkeiten stoßen. Sie könnten immer wieder darauf zurückgreifen, einfach die Eigenschaft zum Prototyp hinzuzufügen, wenn 'defineProperty' nicht funktioniert. – Pointy

+0

@WillP. Ja, vor IE9 konnten die nativen Prototypen in IE nicht geändert werden. – Pointy