I’m starting some work on a rather large JS project and want to make sure I structure the code cleanly and efficiently. I’ve been reading up on a ton of different approaches to OOP in JS and haven’t found one that I really like.
I appreciate the performance improvements offered by using the prototype property, but when you try to add true private methods and variables into the mix it gets rather messy. On the other hand, I really like the closure approach, but I’m not comfortable with the decreased performance. I looked into the module pattern but found it to be pretty verbose. Is there a happy medium somewhere?
To illustrate what I’m struggling with, here are two very small sample classes:
Point Class:
function Point(x, y) {
this.x = x;
this.y = y;
}
// Get the x coordinate.
Point.prototype.getX = function() {
return this.x;
}
// Get the y coordinate.
Point.prototype.getY = function() {
return this.y;
}
// Get the (x, y) coordinate.
Point.prototype.getXY = function() {
return {x: this.x, y: this.y};
}
// Set the x coordinate.
Point.prototype.setX = function(x) {
this.x = x;
}
// Set the y coordinate.
Point.prototype.setY = function(y) {
this.y = y;
}
// Set the (x, y) coordinate.
Point.prototype.setXY = function(x, y) {
this.x = x;
this.y = y;
}
User Class:
function User(guid) {
var guid = guid;
// Return the user's GUID.
this.getGuid = function() {
return guid;
}
}
There will potentially be thousands of point objects in use at any one given time, so I feel like the prototype approach is the best option there. However, if I wanted to add any validation to the setting of coordinates, it could be bypassed by just calling Point.x = <value>. Similarly, I’ll likely be calling Point.getXY() the majority of the time, which will be constructing new objects for what are essentially public properties. Should I get rid of the notion of getters and setters for the Point class and just have it create completely open, public objects? This seems wrong in the context of OOP.
For the User class, I want to store a GUID internally such that it can be requested but never modified. This can’t be done with the prototype approach (unless I’m missing something), so I’m forced into using some sort of closure. I foresee having on the order of hundreds of users active at once, so the performance isn’t as important as it is with the Point class. However, I don’t really want to switch between different types of OOP styles throughout the codebase.
So, as a general question, is there an approach to OOP in JS that I’m missing which would allow me to use the prototype property while cleanly privatizing select functions and variables? Or, am I looking in the wrong direction? Should I be approaching this differently?
You can only use documentation and conventions like
_prefix to mark a method as “internal” but there is no real, enforced private members of objects in javascript.Closures are not acceptable — they will own the data not the objects which can have “interesting” results, especially when one wants to extend a “class” using closures this way.
The other point is that you will use O(n) memory for storing all the function objects which is just unacceptable if it’s out of control for the user of the library who could very easily use the library in a way where it would lead to a memory problem.
You can use underscore prefix convention simply like this: