Mimicking class-based OOP constructors in Javascript
Quick Note: OOP in Javascript is a topic that is beaten to death on Stackoverflow and elsewhere, but I cannot find this specific question answered anywhere.
The "hanging code" in Javascript objects has always bothered me, as it seems to break the flow of the code. What I mean by "hanging code" is the following:
function newObject()
{
var thisObject = this;
// HANGING CODE DOING VARIOUS THINGS SUCH AS
// $('#someDiv').click(function(){}); OR
// var someObje开发者_JAVA技巧ctLiteral = {value:'value'};
}
I wanted to mimic class-based OOP constructors by doing the following:
function newObject()
{
var thisObject = this;
function construct()
{
//WHAT USED TO BE HANGING CODE
}
construct();
}
Is any of the following true or likely to be true about the second methodology:
- It is significantly slower
- It will simply not work at all in certain situations
- It breaks proper coding practice
- It will be harder to debug
- There is a superior methodology to achieve the same result
Thank you.
There is nothing wrong per-se about wrapping code inside an inner function. The only thing you have to watch out is that you can't use this
inside other functions (you need to use an intermediate variable such as yout thisObject
.
Having taken that out of the way, I see no problem at all in having "hanging code" (at least the kind shown in your example). A language such as Java may have trained you to put everything inside a class but in Javascript you only really need to oop-things-up in cases where you explicitly want to take advantage of inheritance or polymorphism.
You probably need to get away from the oop mindset a little. For example, in your case, "hanging code" inside a new object constructor might look bad but I would instead just rename the function to "addClickHandler" or "setLiterals" and call it a day.
You could use something like the MooTools Class which will be slower than your method with the 'hanging' code. This is mostly due to the fact that the MooTools Class has overhead associated with their 'Native' structure. A lot of stuff you may not, and will likely not, need. It sounds like you want something straight-to-the-point.
You could do something like:
var Klass = function(attrs) {
var key, newClass;
attrs = attrs || {};
newClass = function() {
if(this.init) {
this.init.apply(this, Array.prototype.slice.call(arguments));
}
};
for(key in attrs) {
newClass.prototype[key] = attrs[key]
}
return newClass;
};
Then, you could do something like:
var Person = new Klass({
init: function(name, bg) {
this.name = name;
document.getElementById('container').styles.background = bg;
},
speak: function() {
'I am ' + this.name;
}
});
var tim = new Person('tim', 'blue');
// background now blue
tim.speak();
// 'I am tim'
var jane = new Person('jane', 'purple');
// background now purple
jane.speak();
// 'I am jane'
So, this code will fire off the init() when you make a new instance of a class. Passing it whatever arguments. In which you can put your 'hanging' code. Node that, due to the way prototypes work, this does not allow you to make a new instance of a new instance. And you would need to change it further to allow for things like building off of a parent class. But this is a pretty simple way of building a class structure.
This should work fine for what you want. If you were to come across something it "can't do" there will certainly be a way to correct that. You may just have to finagle the code. As I said in the previous paragraph. There will be a little overhead since a class is basically a function being returned, which you then make a new instance of. But nothing too significant. As for best practices, I would say it is not bad. There are a number of JS libraries that have quite extensive class structures in place for you to use. And a lot of people do use classes. But there are and will be arguments over the use of them since they are not real native JS types.
精彩评论