If you have need to create a lot of custom "classes" in your application, I have a few things I've grown to appreciate. In this post I'll talk about a style of class definition that I find readable, provides good encapsulation and can provide good performance when accessing functions on these objects. I'm sure that if I'd worked with JavaScript longer I'd be able to enumerate all the problems with my approach, but so far I don't think there is a lot of down side. But I think part of the reason I like my approach is that it reminds me of Java with less ceremony.
Here's what I usually see around the web:
function MyClass (some, params, needed) { this.doSomeInit(); } var p = MyClass.prototype; //Or = new ParentClass(); p.baz = "lorem"; p.fuzz = "ipsum"; p.foo = function() { return this.baz + this.fuzz; }; p.bar = function() { return this.fuzz + this.baz; };I've also seen:
function MyClass (some, params, needed) { this.doSomeInit(); } MyClass.prototype.baz = "lorem"; MyClass.prototype.fuzz = "ipsum"; MyClass.prototype.foo = function() { return this.baz + this.fuzz; }; MyClass.prototype.bar = function() { return this.fuzz + this.baz; };
So what's going on?
The above code is basically just 2 different ways of defining a JavaScript "class". I put class in quotes because JavaScript doesn't technically have classes. It has objects. My main gripe with these approaches is that it requires that these objects expose a lot of their internal structure by updating their prototype so that these public functions can manipulate the internal state of the object and do work. The only real difference in the 2 styles above is that one is slightly more efficient since it avoids the chaining of object property calls that's required. There is a cost to calling MyClass.prototype each time you define a new function. So if you're looking for speed you put that in a variable.
I prefer to do something like the following:
function MyClass (some, params, needed) { var baz = "lorem"; var fuzz = "ipsum"; function myPrivateFoo() { console.log("PRIVATE"); } this.foo = function () { return baz + fuzz; }; this.bar = function () { myPrivateFoo(); return fuzz + baz; }; }
This approach means that I don't have to expose the variables baz and fuzz. I also get to use the parameters, "some", "params", "needed" without the need to create internal vars or properties on the prototype. The functions foo() and bar() are both public privileged members of our object. It also makes it easy for these public functions to use private functions. My main reasons for liking this approach is that I think it's cleaner in that I like that my constructor encapsulates the class definition like you'd see in Java. I also like that my object can be more shy about what they expose to the world. But is there a downside to this? Actually there is.
The catch is that every time the constructor is called all of the code in my constructor gets run. All the function definitions are added to the prototype every time. That's not so good. Why? Because if your custom object needs to be constructed a lot, then yes you'll take a hit in the performance department. However that's usually a smell of something else not being quite right in the design and can be mitigated with a pattern that separates construction from execution and ensuring you are being judicious about your object creation. However if it truly is something that needs to be created thousands of times, then by all means follow one of the other approaches. Or take a hybrid approach and define any functions that are fully public and don't require internal knowledge of your object state and define them explicitly with the MyClass.prototype.myFunction syntax and anything that has to access the internal state can be defined in the constructor. There's not really a right answer here. I'm just sharing my preference and providing a small argument for it.
If you were to look at performance from another perspective, my approach may actually be preferred. If you are using functions that an object exposes in a loop, or another pattern that requires lots of calls, my approach means that there are fewer property lookups on the object prototype since local variables can be used more often. In practice I find that I'm not constructing custom objects very frequently, but I am calling functions on those objects in loops quite a bit. So for me this approach is a good fit.
Anyone else have a different take? I'd love to hear about it in the comments.