2016-02-01 16 views
8

ho aggiunto il seguente ovatta per Array all'inizio del mio progetto:Aggiungere una funzione al Array.prototype in IE risultati in esso che è spinto in ogni matrice come elemento

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

questo funziona perfettamente bene in Chrome e Firefox, ma su Internet Explorer 11, questa funzione è effettivamente spinto in ogni Array come elemento di esso, e posso persino accedere piace:

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

questo è throwin g tutte le eccezioni in IE con funzioni come .forEach in cui mi aspetto alcuni dati e questa funzione è stata trovata.

Ecco uno screenshot da strumenti di sviluppo di IE, in questo caso, questo array dovrebbe avere solo 2 elementi, invece di 3.

IE - wrong

Ed è così che dovrebbe essere, da Chrome. In effetti, credo che anche il contenuto reale sia sbagliato, ma non ci sono ancora arrivato (dovrebbe essere un array contenente array di lunghezza 2).

Chrome - correct

Come può JavaScript comportarsi ancora così male in IE11, e come posso aggiungere correttamente questa funzione per la prototype invece che in ogni Array esempio?

risposta

16

Non viene "inserito" in tutti gli array; hai aggiunto una proprietà all'oggetto prototipo, quindi è visibile e enumerabile in ogni istanza di array. Ecco come dovrebbero funzionare le proprietà del prototipo.

Funziona in Chrome e Firefox per .find() sul prototipo in quegli ambienti è definito in modo tale da essere visibile ma nonenumerabile. Potete farlo in IE utilizzando 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; 
    } 
    }); 
} 

Oltre alle proprietà "valore", che è chiaramente il valore della nuova proprietà, le proprietà "enumerabile" e default "configurabile" per false. Ciò significa che "find" non verrà visualizzato in nessuna situazione che coinvolga l'iterazione attraverso le proprietà dell'oggetto.

+0

Questa è una grande risposta e funziona! Un'ultima domanda, ho preso questo polyfill da Mozilla Developer's Network (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find#Polyfill) e tutti i loro polyfill usano il stesso approccio di aggiungere direttamente la funzione al prototipo dell'oggetto (un altro esempio: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith#Polyfill). Dovrei evitarlo del tutto e usare sempre 'defineProperty'? O questo sarà solo un problema in 'Array'? –

+1

Personalmente userei 'defineProperty()', anche se stai cercando di far funzionare le cose su IE8 o più vecchio incontrerai delle difficoltà. Si può sempre ricorrere alla semplice aggiunta della proprietà al prototipo se 'defineProperty' non funziona. – Pointy

+0

@WillP. sì, prima di IE9 i prototipi nativi in ​​IE non potevano essere modificati. – Pointy

Problemi correlati