Je voudrais comprendre quand il convient d'utiliser des méthodes prototypes dans js. Doivent-ils toujours être utilisés? Ou y a-t-il des cas où leur utilisation n'est pas préférée et/ou entraîne une baisse des performances?
En parcourant ce site sur les méthodes courantes d'espacement de noms dans js, il semble que la plupart utilisent une implémentation non basée sur un prototype: en utilisant simplement un objet ou un objet fonction pour encapsuler un espace de noms.
Venant d'un langage basé sur les classes, il est difficile de ne pas essayer de faire des parallèles et de penser que les prototypes sont comme des "classes" et les implémentations d'espace de noms que j'ai mentionnées sont comme des méthodes statiques.
Les prototypes sont une optimisation.
Un bon exemple de bien les utiliser est la bibliothèque jQuery. Chaque fois que vous obtenez un objet jQuery en utilisant $('.someClass')
, cet objet a des dizaines de "méthodes". La bibliothèque pourrait y parvenir en renvoyant un objet:
return {
show: function() { ... },
hide: function() { ... },
css: function() { ... },
animate: function() { ... },
// etc...
};
Mais cela signifierait que chaque objet jQuery en mémoire aurait des dizaines d'emplacements nommés contenant les mêmes méthodes, encore et encore.
Au lieu de cela, ces méthodes sont définies sur un prototype et tous les objets jQuery "héritent" de ce prototype de manière à obtenir toutes ces méthodes à un coût d'exécution très faible.
Une partie extrêmement importante de la façon dont jQuery réussit est que cela est caché au programmeur. Il est traité uniquement comme une optimisation, pas comme quelque chose dont vous devez vous soucier lorsque vous utilisez la bibliothèque.
Le problème avec JavaScript est que les fonctions de constructeur nues nécessitent que l'appelant se souvienne de les préfixer avec new
ou sinon elles ne fonctionnent généralement pas. Il n'y a aucune bonne raison à cela. jQuery réussit en cachant ce non-sens derrière une fonction ordinaire, $
, vous n'avez donc pas à vous soucier de la façon dont les objets sont implémentés.
Afin que vous puissiez créer facilement un objet avec un prototype spécifié, ECMAScript 5 inclut une fonction standard Object.create
. Une version grandement simplifiée de celui-ci ressemblerait à ceci:
Object.create = function(prototype) {
var Type = function () {};
Type.prototype = prototype;
return new Type();
};
Il prend juste soin de la peine d'écrire une fonction constructeur puis de l'appeler avec new
.
Quand éviteriez-vous les prototypes?
Une comparaison utile est avec les langages populaires OO tels que Java et C #. Ceux-ci prennent en charge deux types d'héritage:
implement
an interface
de telle sorte que la classe fournit sa propre implémentation unique pour chaque membre du interface.extend
un class
qui fournit des implémentations par défaut de certaines méthodes.En JavaScript, l'héritage prototypique est une sorte d'héritage implémentation. Ainsi, dans les situations où (en C # ou Java) vous auriez dérivé d'une classe de base pour obtenir un comportement par défaut, auquel vous apportez ensuite de petites modifications via des remplacements, puis en JavaScript, l'héritage prototypique a du sens.
Cependant, si vous êtes dans une situation où vous auriez utilisé des interfaces en C # ou Java, vous n'avez pas besoin d'une fonctionnalité de langage particulière en JavaScript. Il n'est pas nécessaire de déclarer explicitement quelque chose qui représente l'interface, ni de marquer les objets comme "implémentant" cette interface:
var duck = {
quack: function() { ... }
};
duck.quack(); // we're satisfied it's a duck!
En d'autres termes, si chaque "type" d'objet a ses propres définitions des "méthodes", il n'y a aucune valeur à hériter d'un prototype. Après cela, cela dépend du nombre d'instances que vous allouez de chaque type. Mais dans de nombreuses conceptions modulaires, il n'y a qu'une seule instance d'un type donné.
Et en fait, il a été suggéré par de nombreuses personnes que l'héritage de l'implémentation est mauvais . Autrement dit, s'il y a des opérations communes pour un type, alors c'est peut-être plus clair si elles ne sont pas placées dans une classe de base/super, mais sont simplement exposées comme des fonctions ordinaires dans un module, auquel vous passez le ou les objets vous voulez qu'ils fonctionnent.
Vous devez utiliser des prototypes si vous souhaitez déclarer une méthode "non statique" de l'objet.
var myObject = function () {
};
myObject.prototype.getA = function (){
alert("A");
};
myObject.getB = function (){
alert("B");
};
myObject.getB(); // This works fine
myObject.getA(); // Error!
var myPrototypeCopy = new myObject();
myPrototypeCopy.getA(); // This works, too.
L'une des raisons d'utiliser l'objet prototype
intégré est que vous dupliquerez plusieurs fois un objet qui partagera des fonctionnalités communes. En attachant des méthodes au prototype, vous pouvez économiser sur les méthodes de duplication créées pour chaque instance de new
. Mais lorsque vous attachez une méthode à prototype
, toutes les instances auront accès à ces méthodes.
Supposons que vous ayez une classe/un objet de base Car()
.
function Car() {
// do some car stuff
}
vous créez ensuite plusieurs instances Car()
.
var volvo = new Car(),
saab = new Car();
Maintenant, vous savez que chaque voiture devra conduire, allumer, etc. Au lieu d'attacher une méthode directement à la classe Car()
(qui occupe de la mémoire pour chaque instance créée), vous pouvez attacher les méthodes au lieu de cela (créer les méthodes une seule fois), donnant ainsi accès à ces méthodes aux nouveaux volvo
et saab
.
// just mapping for less typing
Car.fn = Car.prototype;
Car.fn.drive = function () {
console.log("they see me rollin'");
};
Car.fn.honk = function () {
console.log("HONK!!!");
}
volvo.honk();
// => HONK!!!
saab.drive();
// => they see me rollin'
Mettez des fonctions sur un objet prototype lorsque vous allez créer de nombreuses copies d'un type particulier d'objet et elles doivent toutes partager des comportements communs. Ce faisant, vous économiserez de la mémoire en n'ayant qu'une seule copie de chaque fonction, mais ce n'est que l'avantage le plus simple.
La modification de méthodes sur des objets prototypes ou l'ajout de méthodes modifie instantanément la nature de toutes les instances du ou des types correspondants.
Maintenant exactement pourquoi vous feriez toutes ces choses est principalement fonction de la conception de votre propre application et du genre de choses que vous devez faire dans le code côté client. (Une toute autre histoire serait le code à l'intérieur d'un serveur; beaucoup plus facile d'imaginer y faire du code "OO" à plus grande échelle.)
Si j'explique dans un terme basé sur une classe, alors Person est une classe, walk () est la méthode Prototype. Ainsi, walk () n'aura son existence qu'après avoir instancié un nouvel objet avec ceci.
Donc, si vous voulez créer des copies d'objet comme Person u, vous pouvez créer de nombreux utilisateurs. Le prototype est une bonne solution car il économise de la mémoire en partageant/héritant de la même copie de fonction pour chacun des objets en mémoire.
Alors que l'électricité statique n'est pas d'une grande aide dans un tel scénario.
function Person(){
this.name = "anonymous";
}
// its instance method and can access objects data data
Person.prototype.walk = function(){
alert("person has started walking.");
}
// its like static method
Person.ProcessPerson = function(Person p){
alert("Persons name is = " + p.name);
}
var userOne = new Person();
var userTwo = new Person();
//Call instance methods
userOne.walk();
//Call static methods
Person.ProcessPerson(userTwo);
Donc, avec sa méthode d'instance plus semblable. L'approche de l'objet est similaire aux méthodes statiques.
https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript