2011-01-14 3 views
46

Je crée une classe Vector, qui peut contenir trois valeurs numériques. Cependant, un grand nombre d'opérations peuvent être effectuées sur un tel vecteur - par ex. obtenir la magnitude, ajouter ou soustraire un autre vecteur etc.Devrais-je utiliser un prototype ou non?

Je me demandais si ces fonctions devaient être codées comme étant une fonction prototype de la classe Vector, ou si je devais les définir dans le constructeur.

Alors, laquelle de ces deux méthodes est préférable?

function Vector3D(x, y, z) { 
    this.x = x; 
    this.y = y 
    this.z = z; 
} 

Vector3D.prototype.magnitude = function() { 
    return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); 
}; 

ou

function Vector3D(x, y, z) { 
    this.x = x; 
    this.y = y; 
    this.z = z; 

    this.magnitude = function() { 
     return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); 
    }; 
} 

Répondre

49

C'est exactement la situation pour utiliser un prototype. Je vois deux avantages principaux pour le faire:

  1. fonctions ne sont pas créés plusieurs fois. Si vous définissez les fonctions dans le constructeur, une nouvelle fonction anonyme est créée pour chaque fonction que vous définissez, chaque fois que le constructeur est appelé. Les prototypes sont des objets statiques, et chaque instance de Vector3D va simplement référencer les fonctions du prototype.
  2. Le prototype est un objet unique qui peut être facilement manipulé. Cela offre une grande flexibilité; malheureusement, je ne suis en mesure de fournir quelques exemples de ce que cela peut offrir:
    1. Si vous voulez créer une classe d'enfants, par exemple Vector3DSpecial, vous pouvez simplement cloner Vector3D.prototype et assigner à Vector3DSpecial.prototype. Bien que vous puissiez également le faire en utilisant les constructeurs de Vector3DSpecial.prototype = new Vector3D();, les constructeurs peuvent contenir des effets secondaires qui seront exécutés dans cette affectation prototype simple, et devraient donc être évités. Avec les prototypes, vous pouvez même choisir uniquement des fonctions particulières dans le prototype à copier dans la nouvelle classe.
    2. L'ajout de méthodes à Vector3D consiste simplement à ajouter des propriétés au prototype et permet de diviser/organiser plus facilement votre code en plusieurs fichiers, ou de permettre l'ajout dynamique de méthodes dans d'autres parties du code. Bien sûr, vous pouvez faire une combinaison de méthodes d'ajout dans le constructeur et via le prototype, mais cela est incohérent et risque de conduire à plus de complexité plus loin dans la piste.

Quand dois-je pas usage prototype? Pour les objets singleton, par exemple un contrôleur qui interagit avec une page et peut déléguer du travail à d'autres objets. Un objet "notification" global est un exemple. Ici, l'extension est peu probable et l'objet n'est créé qu'une seule fois, ce qui fait du prototype une complexité supplémentaire (conceptuelle).

8

méthodes prototypé ne fonctionne que pour les propriétés publiques, si vous garder une trace de x, y, z comme variables "privées" le prototype ne fonctionnerait pas.

J'utiliserais ce dernier, parce que vous pourriez vouloir des méthodes qui fonctionnent seulement avec des variables privées/internes, mais tout dépend du contexte.

function Vector3D(x, y, z) { 
    // x, y, z is automatically in this scope now, but as private members. 
    this.magnitude = function() { 
     return Math.sqrt(x * x + y * y + z *z); 
    } 
} 
+1

Merci pour votre réaction. x, y et z devraient aussi pouvoir être extraits d'une instance de Vector3D, ils devraient donc être publics. Dans ce cas, le prototype serait-il le meilleur choix? – pimvdb

+3

+1 pour la réponse correcte, mais je préfère les prototypes, car quoi que ce soit privé dans js est une chimère, et généralement plus difficile pour vous à l'unité de tester votre code - qui cachez-vous les choses de vous, sauf :) –

+0

Je suis d'accord avec vous, donc je n'ai que des variables publiques. Dans Google Chrome Developer Tools, les fonctions sont affichées en tant que membres si elles sont transmises par le constructeur, alors que ce serait plus pratique si elles étaient cachées dans le prototype et que seulement x, y et z apparaîtraient là. – pimvdb

0

ECMA 6 http://es6-features.org/#BaseClassAccess

class Shape { 
    … 
    toString() { 
     return `Shape(${this.id})` 
    } 
} 
class Rectangle extends Shape { 
    constructor (id, x, y, width, height) { 
     super(id, x, y) 
     … 
    } 
    toString() { 
     return "Rectangle > " + super.toString() 
    } 
} 
class Circle extends Shape { 
    constructor (id, x, y, radius) { 
     super(id, x, y) 
     … 
    } 
    toString() { 
     return "Circle > " + super.toString() 
    } 
} 

ECMA 5

var Shape = function (id, x, y) { 
    … 
}; 
Shape.prototype.toString = function (x, y) { 
    return "Shape(" + this.id + ")" 
}; 
var Rectangle = function (id, x, y, width, height) { 
    Shape.call(this, id, x, y); 
    … 
}; 
Rectangle.prototype.toString = function() { 
    return "Rectangle > " + Shape.prototype.toString.call(this); 
}; 
var Circle = function (id, x, y, radius) { 
    Shape.call(this, id, x, y); 
    … 
}; 
Circle.prototype.toString = function() { 
    return "Circle > " + Shape.prototype.toString.call(this); 
}; 
Questions connexes