I'd like to start by saying that I understand that JavaScript is a Classless language. My background is in Java, C++, and Objective-C which are all classic OOP languages that support Classes.
I'm expanding into Web Development and have been experimenting with JavaScript and learning its Patterns. Right now I'm working with the Constructor Pattern that simulates Classes with in JavaScript.
So this is my "practice" class:
function Car( model, year, miles ) {
this.model = model;
this.year = year;
this.miles = miles;
var privateVarTest = 10;
this.getPrivateVarTest = function() {
return privateVarTest;
}
this.setPrivateVarTest = function( value ) {
privateVarTest = value;
}
}
Car.prototype.toString = function() {
return this.model + " is a " + this.year + " model and has " +
this.miles + " miles.";
}
var myCar = new Car( "Ford Focus", "2006", "65,000" );
document.getElementById('notepad').innerHTML += '</br> Testing </br>';
document.getElementById('notepad').innerHTML += myCar.toString() + '</br>';
document.getElementById('notepad').innerHTML += myCar.model + '</br>';
document.getElementById('notepad').innerHTML += myCar.getPrivateVarTest() + '</br>';
myCar.setPrivateVarTest( 20 );
document.getElementById('notepad').innerHTML += myCar.getPrivateVarTest() + '</br>';
Now I like using the prototype
way of defining functions, as it doesn't instantiate a new version of the function for each Car
Object created. However, in classic OOP languages we make our variables private
and create public
functions/methods to set and get these variables as needed.
JavaScript being Classless there is no private
or public
key word for this use, so I thought I'd experiment with a method of "faking" a private
variable, and that's when found that using var
instead of this
essential makes it unaccessible out side of the constructor
, but I was able to define getters and setters that would allow me to.
Now finaly to my question, sorry about the long wind up. For Best Practices from experinced JavaScript programmers, would you make all variables private
to follow the standards of other OOP languages, and set getters and setter (which can not be prototyped forcing a creation for each Object), or avoid them as much as possible since the this
keyword basicly lets you get and set all you want, and ONLY use private
for hard coding some internal data needed for the class?
Thank you for taking the time to read this and providing to the discussion, I'm really just trying to get a feel for the standards that are used as Best Practices by experinced Web Developers.
General OOP
I'm in the camp that getters and setters are largely completely pointless and silly regardless of what language you're writing code in.
For the most part, exposed properties should be rare since any property of an object should typically be within the object's domain so only the object should actually change its own internals as a side-effect of other actions, not because some other object directly told it to change something. There are exceptions I'm sure (there always are) but I can't remember the last time I needed to make one.
Furthermore, when properties are exposed, the only reason to expose with a method is because you either can't just expose the property due to language constraints (Java) or because some validation or notification has to happen when you change that property. Just tacking on methods Java-bean-style that do nothing more than actually alter or return properties does nothing to preserve encapsulation. You might as well just make the property public if you can.
But the real problem with wanting to get/set everything willy-nilly from all over the place is that you've basically just written chained procedural code and called it OOP. You still have a long winding series of things that can only be reasoned about in terms of one happening after the other. With OOP, the idea is to avoid that long winding spaghetti chain so you can view your architecture more from the perspective of larger constructs that own specific domains interacting with each other at key points. Without that, you're perhaps reducing the spaghetti a touch by at least categorizing your functions under namespaces so it's easier to know where to look for stuff but you're not really leveraging the key wins that OOP can provide your architecture.
The real value of private or in JS's case local constructor/factory-closur vars is signalling intent. If it's exposed, something external really should be changing it. If it isn't, then you've made it clear that the var is only the object's business.
JS OOP
My advice is to forget class-emulation in JS. It's completely unnecessary. Prototypes are elegant and easy once you understand them. Think of a constructor's prototype property as a kind of a backup object. If you call a method on an instance that it doesn't have, the next step is to check the instance's constructor's prototype object property. If that object doesn't have it, then its constructor's prototype object gets checked and so on until you finally reach the core Object constructor's prototype.
It's because of that lookup process that you can add new methods to a constructor on the fly and have all instances "inherit" it after they've been built but it's not really inheritance so much as a fallback process.
Inheritance in JS is stupid-easy. That doesn't mean you should do a ton of it though. Long chains of cascading inheritance is regarded as an anti-pattern in any language for good reason and due to the way the callback process works, it can also really kill perf if you're hammering on the call object through like 18 levels of prototypes for every little thing in JS. I would say prefer composite objects to inheritance and when inheritances seems like a wiser option, check yourself any time you're tempted to inherit through more than 2-3 prototype links in the chain.
Oh, and one JS gotcha to look out for on local instance vars in the constructors as private properties: that's just JS's closure rules within a function scope context in action really. Methods declared in the prototype or outside of the constructor function can't access those internal vars. Constructor functions invoked with the new keyword change the rules of what 'this' accesses and they leave an instance behind but are otherwise executed JS functions in every other way.
Other flavors of crazy but also crazy-powerful worth understanding in JS OOP are the apply, call, and now bind methods. I tend to see these more as things you'd want in a factory but they are very powerful.
Once you've mastered JS OOP, start understanding JS from a functional perspective and you'll discover it has a really powerful 1-2 punch combo going on. We can do just about anything very easily and with a minimum of code in JS. The design tradeoff is performance (which modern JIT compilers are handling surprisingly well) and that it gives you plenty of rope to hang yourself with. I prefer the rope. The self-lynching is no fun but that's part of the learning/developing better instincts process which happens much faster as a result and leads to more maintainable code in the long haul. Whereas Java basically forces OOP implementation but due to being overly protectionist in regards to devs doing dumb things to themselves, results in community wide adoption of practices that run completely counter to the whole point of OOP.
The short version:
Update:
The es6 class keyword changes virtually nothing about OOP in JS. It's 100% syntax-sugar. IMO, the use of the word "class" isn't doing newcomers any favors but there are advantages/disadvantages to all three styles of object constructor/creation and object instantiation in JS and they're all worth knowing/understanding. Those three approaches are functions as constructors, Object.create, and now the class keyword.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With