Javascript Simple de l'héritage à l'aide de $.étendre et motif de module
J'ai demandé pour un couple d'années maintenant, ce que pensent les gens de faire de l'héritage avec un module-pattern-esque constructeur de motif et SANS des prototypes de l'héritage. Pourquoi les programmeurs de ne pas utiliser un module de modèle pour les non-singleton js les classes? Pour moi les avantages sont:
- Très clair publics et privés de la portée (facile à comprendre le code et de l'api)
- Pas besoin de suivre le " ce " pointeur via $.proxy(fn, c') des rappels
- Pas plus var que = ce, etc. avec les gestionnaires d'événements, etc. Chaque fois que je vois un "il", je sais que c'est le contexte qui est passé dans une fonction de rappel, il n'est PAS quelque chose que je suis suivi de la connaissance de mon instance de l'objet.
Inconvénients:
- Petite perf dégradation
- Risque possible "remuer du doigt" de Doug Crockford?
Envisager (juste courir dans tous les js console)
var Animal = function () {
var publicApi = {
Name: 'Generic',
IsAnimal: true,
AnimalHello: animalHello,
GetHelloCount:getHelloCount
};
var helloCount = 0;
function animalHello() {
helloCount++;
console.log(publicApi.Name + ' says hello (animalHello)');
}
function getHelloCount(callback) {
callback.call(helloCount);
}
return publicApi;
};
var Sheep = function (name) {
var publicApi = {
Name: name || 'Woolie',
IsSheep: true,
SheepHello: sheepHello
};
function sheepHello() {
publicApi.AnimalHello();
publicApi.GetHelloCount(function() {
console.log('i (' + publicApi.Name + ') have said hello ' + this + ' times (sheepHello anon callback)');
});
}
publicApi = $.extend(new Animal(), publicApi);
return publicApi;
};
var sheepie = new Sheep('Sheepie');
var lambie = new Sheep('Lambie');
sheepie.AnimalHello();
sheepie.SheepHello();
lambie.SheepHello();
Ma question est: quels sont les inconvénients à cette approche que je ne suis pas le voir? Est-ce une bonne approche?
Merci!
[mise à jour]
Merci pour les excellentes réponses. Souhaite que je pourrais donner à chacun la bounty. C'était ce que je cherchais. Fondamentalement, ce que je pensais. Je n'aurais jamais utiliser le module de modèle à construire plus de quelques cas de quelque chose. Habituellement, seulement un couple. La raison pour laquelle je pense qu'il a ses avantages est toute petite perf dégradation de vous voir qui est repris dans la simplicité de la programmation. Nous avons BEAUCOUP de code à écrire ces jours-ci. Nous avons également de réutiliser des autres peuples code et personnellement j'apprécie quand quelqu'un a pris le temps de créer un joli modèle élégant, plutôt que dogmatique, en adhérant à des prototypes de l'héritage lorsque cela a du sens.
Vous devez vous connecter pour publier un commentaire.
Je pense qu'il se résume à la question de la performance. Vous avez mentionné qu'il y a un petit dégradation des performances, mais cela dépend vraiment de l'ampleur de la demande(2 moutons vs 1000 moutons). Prototypes héritage ne doit pas être ignoré et nous pouvons créer un motif de module à l'aide d'un mélange de fonctionnel et prototypes héritage.
Comme mentionné dans le post JS - Pourquoi utiliser le Prototype?,
une des beautés de prototype est que vous avez seulement besoin de initialiser les prototypes membres qu'une seule fois,
attendu que les membres dans le constructeur sont créés pour chaque instance.
En fait, vous pouvez accéder prototype directement sans créer un nouvel objet.
Dans vos fonctions, il y a une charge supplémentaire de créer un tout nouveau
Des animaux et des moutons à chaque fois qu'un constructeur est appelé. Certains membres comme des Animaux.nom sont créés avec chaque instance, mais nous savons
cet Animal.le nom est statique, de sorte qu'il serait mieux pour instancier qu'une seule fois. Depuis votre code implique que l'Animal.nom
doit être la même pour tous les animaux, il est facile de mettre à jour l'Animal.nom pour tous instance simplement en mettant à jour l'Animal.le prototype.nom si nous avons déménagé
il est le prototype.
Considérer cette
Fonctionnelle héritage/Motif de Module
vs Prototype
Comme indiqué ci-dessus avec votre motif de module de nous perdre en efficacité
la mise à jour des propriétés qui doivent être communes à tous les membres.
Si vous êtes concered sur visibilité, je voudrais utiliser la même méthode modulaire vous êtes en train d'utiliser pour encapsuler les membres privés, mais également de l'utiliser
privilégiée membres pour l'accès à ces membres s'ils ont besoin d'être atteint. Privilégiée membres sont des membres du public qui fournissent une interface pour accéder aux variables privées. Ajoutez enfin les communes membres du prototype.
Bien sûr d'aller dans cette voie, vous aurez besoin de garder une trace de ce.
Il est vrai que la mise en œuvre, il est
mais vous êtes la création d'un très grand objet à chaque fois qui consomment plus de mémoire en comparaison à l'utilisation de certains prototypes héritage.
Cas de la Délégation, comme Analogie
Un analogie de gagner en performance en utilisant des prototypes est l'amélioration de la performance en utilisant événement délégation lors de la manipulation du DOM.Événement Délégation en Javascript
Permet de dire que vous avez une grande liste d'épicerie.Yum.
Disons que vous voulez enregistrer l'élément que vous cliquez sur.
Une mise en œuvre serait de associer un gestionnaire d'événement pour chaque élément(mauvais), mais si notre liste est très longue, il y aura beaucoup d'événements à gérer.
Une autre mise en œuvre serait de attacher un gestionnaire d'événement pour le parent(bon) et ont que l'un des parents de gérer toute la clique.
Comme vous pouvez le voir c'est similaire à l'utilisation d'un prototype pour la commune de fonctionnalités et améliore sensiblement les performances
Réécrire à l'aide de la Combinaison de la Fonctionnelle/Prototypes Héritage
Je pense que la combinaison de la fonctionnelle/prototypes de succession peuvent être écrites dans un format facile compréhensible.
J'ai réécrit votre code en utilisant les techniques décrites ci-dessus.
Conclusion
La vente à emporter est à utiliser à la fois les prototypes et fonctionnelle de l'héritage à leurs avantages à la fois pour s'attaquer à la performance et la visibilité des questions.
Enfin, si vous travaillez sur un petites applications JavaScript et ces problèmes de performances ne sont pas une préoccupation,
ensuite, votre méthode de l'approche viable.
Animal.prototype.updateName('NewName');
ne pas modifier tous les animaux, il modifie uniquement l'Generic
nom hérité par tous les d'entre eux. Btw, votre combinaison de script contient certaines mauvaises pratiques, ne fonctionne pas dans tous les cas et utilise encore fonctionnel/parasites héritage pourSheep
. Il ne montre pas tout les avantages de l'OP, un...Animal.prototype.updateName('NewName')
seulement la mise à jour de laGeneric
nom", mais c'est l'effet voulu. Tous les moutons ont un nom générique(car ils sont toujours des animaux) et leur nom propre.Animal.Name
ouAnimal.IsAnimal
et certaines propriétés comme Nom sont remplacés plus tard. Pour prendre la pleine capacité de $.étendre je pense que le code doit être utilisé de sorte que la mesure n'intervient qu'une fois à construire une base de Mouton objet, puis le constructeur/la fonction devrait être utilisée pour initialiser les valeurs(comme lamakeSheep
fonction vous décrit) au lieu de faire redondant extensions à chaque fois.Ceci est connu comme parasitaires héritage ou fonctionnelle de l'héritage.
La même chose vaut pour le classique constructeur modèle. Btw, dans votre code actuel, c'est pas super clair si
animalHello
etgetHelloCount
sont censé être privé ou non. La définition de leur droit à l'objet exporté littérale pourrait être mieux si vous vous souciez que.Qui est fondamentalement la même. Soit vous utilisez un
that
de déréférencement ou de liaison pour résoudre ce problème. Et je ne vois pas cela comme un énorme inconvénient, car la situation où vous devez utiliser l'objet "méthodes" directement comme des callbacks sont assez rares et en dehors du contexte vous souhaitez souvent de nourrir des arguments supplémentaires. Btw, vous êtes à l'aide d'unthat
de référence aussi bien dans votre code, il est appelépublicApi
là.Maintenant, vous avez mentionné quelques-uns des inconvénients vous-même déjà. En outre, vous êtes perdant de l'héritage par prototype - avec tous ses avantages (simplicité, dynamisme,
instanceof
, ...). Bien sûr, il y a des cas où ils ne s'appliquent pas, et votre fonction de fabrication est parfaitement bien. Il est en effet utilisé dans ces cas.Ces parties de votre code sont un peu déroutant ainsi. Vous êtes d'écraser la variable dont l'objet est différent ici, et ça se passe dans le milieu à la fin de votre code. Il serait mieux de voir cela comme une "déclaration" (vous êtes hérite les propriétés parent ici!) et le mettre en haut de votre fonction de droite comme
var publicApi = $.extend(Animal(), {…});
Aussi, vous ne devez pas utiliser le
new
mot-clé ici. Vous n'utilisez pas les fonctions que les constructeurs, et vous ne voulez pas de créer des instances qui héritent deAnimal.prototype
(ce qui ralentit votre exécution). Aussi, il confond les personnes qui pourraient s'attendre à l'héritage par prototype à partir de ce constructeur invocation avecnew
. Pour plus de clarté, vous pourriez même renommer les fonctions demakeAnimal
etmakeSheep
.Ce modèle de conception est complètement de l'environnement. Il travaillera en Node.js tout comme comme comme chez le client et dans tous les autres EcmaScript mise en œuvre. Certains aspects de ce même sont indépendants de la langue.
instanceof
où vous aveztypeof
? Avec ou sans les prototypes de l'héritage,typeof
n'est que va vous donner"object"
ou"function"
, jamais"Animal"
ouAnimal
.Avec votre approche, vous ne serez pas en mesure de remplacer des fonctions et d'appeler la fonction super facilement.
Aussi, dans le prototype approche, vous pouvez partager des données au sein de toutes les instances de l'objet.
Un autre avantage de l'approche par prototype serait pour économiser de la mémoire.
Alors que dans votre approche,
Cela signifie à chaque nouvel objet, une nouvelle instance de l'fonctions sont créés où, comme il est partagé entre tous les objets en cas de prototype approche.
Ce ne sera pas beaucoup de différence en cas de rares cas, mais lorsqu'un grand nombre d'instances sont créées, ce serait montrer une différence considérable.
Aussi, une plus puissante fonction de prototype serait une fois tous les objets sont créés, vous pouvez toujours modifier les propriétés parmi tous les objets à la fois (uniquement si elles ne sont pas modifiées après la création de l'objet).
Conclusion:
Si les avantages mentionnés ci-dessus du prototype approche ne sont pas si utiles pour votre application, votre approche serait mieux.
function Bar() { var that = Foo(), superValue = that.value; that.value = function() { return superValue()+" overwritten"; }; return that; }