Google JavaScript Style Guide déconseille l'extension du Array.prototype
. Cependant, j'ai utilisé Array.prototype.filter = Array.prototype.filter || function(...) {...}
comme moyen de l'avoir (et des méthodes similaires) dans les navigateurs où ils n'existent pas. MDN fournit en fait exemple similaire .
Je suis au courant des problèmes de Object.prototype
, Mais Array
n'est pas une table de hachage.
Quels problèmes peuvent survenir lors de l'extension de Array.prototype
Qui ont déconseillé Google de le faire?
La plupart des gens ont raté le point sur celui-ci. Fonctionnalité standard de remplissage ou de calage comme Array.prototype.filter
pour que cela fonctionne dans les anciens navigateurs est une bonne idée à mon avis. N'écoutez pas les ennemis. Mozilla vous montre même comment faire cela sur le MDN. Habituellement, les conseils pour ne pas étendre Array.prototype
ou d'autres prototypes natifs peuvent se résumer à l'un d'eux:
for..in
peut ne pas fonctionner correctementVoici mes réponses:
for..in
sur Array est généralement. Si vous le faites, vous pouvez utiliser hasOwnProperty
pour vous assurer qu'il est légitime.Array.prototype.filter
.Object.keys
à IE7. Il semblait cesser de fonctionner dans certaines circonstances. Votre kilométrage peut varier.Découvrez ces références:
Bonne chance!
Je vais vous donner les puces, avec des phrases clés, de l'excellent article de Nicholas Zakas JavaScript maintenable: ne modifiez pas les objets que vous ne possédez pas :
Fondamentalement, ne le faites pas. Même si votre projet ne sera jamais utilisé par quelqu'un d'autre et que vous n'importerez jamais de code tiers, ne le faites pas. Vous établirez une horrible habitude qui pourrait être difficile à briser lorsque vous commencez à jouer à Nice avec les autres.
En tant que mise à jour moderne de la réponse de Jamund Ferguson:
Habituellement, les conseils pour ne pas étendre Array.prototype ou d'autres prototypes natifs peuvent se résumer à l'un de ces éléments:
- for..in pourrait ne pas fonctionner correctement
- Quelqu'un d'autre peut également vouloir étendre Array avec le même nom de fonction
- Cela pourrait ne pas fonctionner correctement dans tous les navigateurs, même avec la cale.
Les points 1. et 2. peuvent maintenant être atténués dans ES6 en utilisant un Symbol pour ajouter votre méthode.
Cela crée une structure d'appel légèrement plus maladroite, mais ajoute une propriété qui n'est pas répétée et qui ne peut pas être facilement dupliquée.
// Any string works but a namespace may make library code easier to debug.
var myMethod = Symbol('MyNamespace::myMethod');
Array.prototype[ myMethod ] = function(){ /* ... */ };
var arr = [];
// slightly clumsier call syntax
arr[myMethod]();
// Also works for objects
Object.prototype[ myMethod ] = function(){ /* ... */ };
Avantages:
Les inconvénients:
Étendre Array.prototype
Dans votre propre code d'application est sûr (sauf si vous utilisez for .. in
Sur des tableaux, auquel cas vous devez payer pour cela et vous amuser à les refactoriser).
Il n'est pas cool d'étendre des objets Host natifs dans des bibliothèques que vous avez l'intention d'utiliser par d'autres. Vous n'avez pas le droit de corrompre l'environnement d'autres personnes dans votre propre bibliothèque.
Faites cela derrière une méthode facultative comme lib.extendNatives()
ou ayez [].filter
Comme exigence.
Prototype fait cela. C'est mal. L'extrait de code suivant montre comment cela peut produire des résultats inattendus:
<script language="javascript" src="https://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js"></script>
<script language="javascript">
a = ["not", "only", "four", "elements"];
for (var i in a)
document.writeln(a[i]);
</script>
Le résultat:
not only four elements function each(iterator, context) { var index = 0; . . .
et environ 5000 caractères de plus.
Certaines personnes utilisent for ... in
boucles pour parcourir les tableaux. Si vous ajoutez une méthode au prototype, la boucle tentera également d'itérer sur la clé that. Bien sûr, vous ne devriez pas l'utiliser pour cela, mais certaines personnes le font quand même.
Vous pouvez facilement créer une sorte de sandbox avec la bibliothèque poser
.
Jetez un oeil sur https://github.com/bevacqua/poser
var Array2 = require('poser').Array();
// <- Array
Array2.prototype.eat = function () {
var r = this[0];
delete this[0];
console.log('Y U NO .shift()?');
return r;
};
var a = new Array2(3, 5, 7);
console.log(Object.keys(Array2.prototype), Object.keys(Array.prototype))
L'extension du prototype est une astuce qui ne fonctionne qu'une seule fois. Vous faites et vous utilisez une bibliothèque qui le fait aussi (de manière incompatible) et boom!
La fonction que vous remplacez pourrait être utilisée par les appels javascript internes et cela pourrait conduire à des résultats inattendus. C'est l'une des raisons de la directive
Par exemple, j'ai outrepassé la fonction indexOf du tableau et il a gâché l'accès au tableau à l'aide de [].
Je crois que cette question mérite une réponse mise à jour ES6 .
ES5
Tout d'abord, comme beaucoup de personnes l'ont déjà dit. L'extension des prototypes natifs pour caler ou remplir de nouvelles normes ou corriger des bogues est une pratique standard et n'est pas nuisible. Par exemple, si un navigateur ne prend pas en charge la méthode .filter if (!Array.prototype.filter)
, vous êtes libre d'ajouter cette fonctionnalité par vous-même. En fait, le langage est conçu pour faire exactement cela pour gérer la compatibilité descendante.
Maintenant, vous pardonneriez de penser que puisque l'objet JavaScript utilise l'héritage prototypique, étendre un objet natif comme Array.prototype
Sans interférer devrait être facile, mais jusqu'à ES6 ce n'était pas faisable.
Contrairement aux objets par exemple, vous avez dû compter et modifier le Array.prototype
Pour ajouter vos propres méthodes personnalisées. Comme d'autres l'ont souligné, c'est mauvais car il pollue l'espace de noms Global, peut interférer avec d'autres codes de manière inattendue, a des problèmes de sécurité potentiels, est un péché cardinal, etc.
Dans ES5, vous pouvez essayer de pirater cela, mais les implémentations ne sont pas vraiment utiles. Pour des informations plus détaillées, je vous recommande de consulter ce post très informatif: http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/
Vous pouvez ajouter une méthode à un tableau, ou même un constructeur de tableau, mais vous rencontrez des problèmes en essayant de travailler avec les méthodes de tableau natives qui reposent sur la propriété length. Pire encore, ces méthodes vont retourner un Array.prototype
Natif et non votre nouveau tableau de sous-classes brillant, c'est-à-dire: subClassArray.slice(0) instanceof subClassArray === false
.
ES6
Cependant, maintenant avec ES6, vous pouvez sous-classer les buildins en utilisant class
combiné avec extends Array
Qui surmonte tous ces problèmes. Il laisse le Array.prototype
Intact, crée une nouvelle sous-classe et les méthodes de tableau dont il hérite seront de la même sous-classe! https://hacks.mozilla.org/2015/08/es6-in-depth-subclassing/
Voir le violon ci-dessous pour une démonstration: https://jsfiddle.net/dmq8o0q4/1/