It’s time for another episode of the Up the Moo Herd: MooTools Tips and Tricks series, where we’ll talk about classes, the backbone of MooTools. Other JS libraries thrive using plugins and extensions, but MooTools keeps its object-oriented focus by using classes and mixins to new functionality to the framework.
Due to length concerns, I split up the article on classes into two parts. This one tackles constructors, implement and extend, singletons, and private methods and variables. The next part will deal with mutators, mixins, inheritance and reusable code.
I went directly to the various tips and tricks that involve classes in this post rather than explain the basics. If you get lost, it might be good to get a firmer grasp on how classes work. The series introduction linked above contains links to tutorials and sites that would help you to do just that.
The title for this post is taken from Breathe Carolina’s second album, which I was listening to while writing this article. They’re a really awesome band, and I admire them for being able to make Miley Cyrus’ “See You Again” palatable.
With that, let’s start getting classy!
Getting Classy
Class is the constructor used for creating classes in MooTools. There are two ways to create a class, the first being the standard way, which is available since version 0.87 (maybe even older—but that’s the version I could verify without digging too much). This involves passing an object that acts as the prototype of the class:
// standard way of creating classes:
var Barn = new Class({
initialize: function(name){
this.fowl = name;
},
getFowl: function(){
return this.fowl;
},
setFowl: function(name){
this.fowl = name;
return this;
}
});
var myBarn = new Barn('chicken');
myBarn.getFowl(); // returns 'chicken'
myBarn.setFowl('turkey')
myBarn.getFowl(); // returns 'turkey'
The second way comes from the new Class/Class.js, which was overhauled in MooTools 1.2.2. From this version onwards, Class will accept a function that will become your initialize method instead of an object:
// alternative, constructor based way:
var Barn = new Class(function(name){
this.fowl = name;
});
Barn.implement({
getFowl: function(){
return this.fowl;
},
setFowl: function(name){
this.fowl = name;
return this;
}
});
var myBarn = new Barn('chicken');
myBarn.getFowl(); // returns 'chicken'
myBarn.setFowl('turkey')
myBarn.getFowl(); // returns 'turkey'
This alternative way might look alien at first, but it opens up new possibilities that we’ll use later.
Implement and Extend
Classes have an implement method used to add new methods. Similar to the implement function in Natives, it can be used in two ways:
// key-value way..
Barn.implement('feedFowl', function(){...});
// hash way..
Barn.implement({
feedFowl: function(){
...
},
prepareFowl: function(){
...
}
});
Always use the second syntax if you’re adding multiple methods to avoid repeated calls to implement.
Classes also have an extend method. While implement adds methods to the prototype of the class, extend adds methods to the class constructor itself. In other words, implement creates instance methods and members, extend creates class methods and variables:
var Barn = new Class();
// instance method using implement..
Barn.implement({
instanceMethod: function(){
return 'From an instance!';
}
});
// class method using extend..
Barn.extend({
classMethod: function(){
return 'From the class itself!';
}
});
var myBarn = new Barn();
typeof(myBarn.instanceMethod); // returns 'function'
myBarn.instanceMethod(); // returns 'From an instance!'
typeof(myBarn.classMethod); // returns 'undefined'
typeof(Barn.classMethod); // returns 'function'
Barn.classMethod(); // returns 'From the class itself!'
typeof(Barn.instanceMethod); // returns 'undefined'
extend is a very useful method, especially if you want to keep your code clean. Instead of doing this:
var Barn = new Class();
Barn.fowlCount = 0;
Barn.countFowls = function(){
return Barn.fowlCount;
};
Barn.addFowl = function(){
Barn.fowlCount += 1;
};
You can do this instead:
var Barn = new Class();
Barn.extend({
fowlCount: 0,
countFowls: function(){
return this.fowlCount;
},
addFowl: function(){
this.fowlCount += 1;
}
});
Your Class Just Changed His Status to Single(ton)
There are several available techniques for creating singletons, so let me share the ones I know and I’ve used before.
The first one is the easiest and the best solution: use an object:
// Create the singleton object..
var Singleton = {
greeting: 'Howdy ',
greet: function(name){
return [this.greeting, name, '!'].join(' ');
}
};
Singleton.greet('Mark'); // returns 'Howdy Mark!';
// this will throw an error because Singleton is not a constructor.
var newSingleton = new Singleton();
But how about mixins like Events? Use the $extend function:
// Create the singleton object..
var Singleton = {
name: 'Mark',
greeting: 'Howdy'
greet: function(name){
return [this.greeting, name || this.name, '!'].join(' ');
}
};
$extend(Singleton, new Events());
Singleton.addEvent('greet', function(){
this.greet('Joseph'); // returns 'Howdy Joseph!'
this.greet(); // returns 'Howdy Mark!'
});
Singleton.fireEvent('greet');
There’s also a way to get singletons by using vanilla MooTools classes. The way to do that is to keep your class declaration inside a closure, create a local variable to hold the instance to your singleton and use that for every call:
(function(){
// variable for holding the instance..
var instance = null;
this.Singleton = new Class({
initialize: function(name){
if (instance) return instance;
this.name = name;
instance = this;
},
getName: function(){
return this.name;
}
});
})();
var mySingleton = new Singleton('Mark');
mySingleton.getName(); // returns 'Mark';
var newSingleton = new Singleton('Joseph');
newSingleton.getName(); // returns 'Mark';
// both instances refer to the same object..
mySingleton == newSingleton;
The second one has the benefit of having a familiar syntax, and mixins and other class features work without having to use a different technique. But because it’s still a class, your singleton will have a public constructor available, so make sure that you document that it’s a singleton. It’ll be confusing for other people who’ll try to use your code when they create new instances and fail—so document!
Another way is the double new operator hack:
var Singleton = new new Class({...})
What happens here is that the second new operator is used to create an new Class, which returns a constructor function for the class. The first new is used to create a new instance of the class. To avoid confusion and to allow for passing constructor variables, you can group them into parentheses.
var Singleton = new (new Class({
initialize: function(name){
this.name = name;
},
getName: function(){
return this.name;
}
}))('Mark');
Singleton.getName(); // returns 'Mark'
// This throws an error..
new Singleton('Joseph');
Keeping Secrets
Closures are the easiest way to create private variables. You can wrap the class declaration in a closure and declare your private variables inside it to create a local scope:
(function(){
var secret = 'I like bacon.';
this.Secretive = new Class({
getSecret: function(){
return secret;
},
setSecret: function(newSecret){
secret = newSecret;
return this;
}
});
})();
var secret = new Secretive();
typeof(secret.secret); // returns 'undefined'
secret.getSecret(); // returns 'I like bacon.'
secret.setSecret('I like bacon too!');
secret.getSecret(); // returns 'I like bacon too!'
I mentioned a few paragraphs ago that MooTools 1.2.2 and above allows passing a constructor function to Class rather than a prototype object. This feature gives us another way to create private variables:
var Secretive = new Class(function(){
var secret = 'I like bacon.';
$extend(this, {
getSecret: function(){
return secret;
},
setSecret: function(newSecret){
secret = newSecret;
return this;
}
});
});
var secret = new Secretive();
typeof(secret.secret); // returns 'undefined'
secret.getSecret(); // returns 'I like bacon.'
secret.setSecret('I like bacon too!');
secret.getSecret(); // returns 'I like bacon too!'
You might notice that we use $extend inside the function because this.implement wouldn’t be available inside the constructor function. You can still use implement after you declared your constructor, but make sure that any function that needs access to the private variable are declared inside the constructor. Otherwise, it’ll be out of scope and you won’t be able to access the variable.
Can’t Touch This!
The same techniques for creating private variables can be used to create private methods. Here’s one involving a closure:
(function(){
// our private method..
var secretFunction = function(){
return 'The cake is a lie.';
};
this.Secretive = new Class({
tellSecret: function(){
return secretFunction();
}
});
})();
var secrets = new Secretive();
secrets.tellSecret(); // returns 'The cake is a lie.'
typeof(secrets.secretFunction); // returns 'undefined'
And here’s one using the new MooTools feature of passing a constructor function:
var Secretive = new Class(function(){
// our private method..
var secretFunction = function(){
return 'The cake is a lie.';
};
$extend(this, {
tellSecret: function(){
return secretFunction();
}
});
});
var secrets = new Secretive();
secrets.tellSecret(); // returns 'The cake is a lie.'
typeof(secrets.secretFunction); // returns 'undefined'
Fortunately, you don’t need to use the techniques above because of a new feature that arrived in MooTools 1.2.2. It solves the problem of creating private methods using a new Function method called protect. What it does is it sets some variables on your function that makes it impossible to call the method from the outside of a class. It will still be visible, but it can’t be invoked:
var Secretive = new Class({
secretFunction: (function(){
return 'The cake is a lie.';
}).protect(),
tellSecret: function(){
return this.secretFunction();
}
});
var secrets = new Secretive();
secrets.tellSecret(); // returns 'The cake is a lie.'
typeof(secrets.secretFunction); // returns 'function'
secrets.secretFunction(); // Error: 'The method secretFunction cannot be called.'
protect is an exciting addition to MooTools because we now get true protected methods without using complex closures. Awesome, right?
Class Just Ended
This concludes this episode of the Up the Moo Herd. I hope you learned some new tricks to add to your MooTools repertoire. If you have tips and tricks related to the ones I presented above, make sure you post it on the comments. It’ll be awesome to hear from you!
In the next part of the series, we’ll talk more about classes, with focus on mixins, mutators and reusable code, so don’t forget to subscribe to the RSS feed and follow me on Twitter (@keeto) for updates.
Reactions
post your reactionHarald
I can’t give enough kudos to you, Mark! You are doing such an awesome work with this series, very classy! Easy to understand, a lot of details … lets your readers understand how to use and to see behind the curtain!
Kevin
Great post Mark, I’ve learned some new things here ! Thnx ;-)
Greetings from Belgium ^^
Martin
Nice article - again!! Thanks a lot! I found two minor errors in the first and second example at line 24: ‘myBarn.getName()’ should be ‘myBarn.getFowl()’, right?
Mark Obcena
@Harald: Thanks! Most MooTools articles seem to fall under the beginner or expert levels, and I really wanted to fill the gap between them with this series. I enjoy writing these articles a lot, and I hope readers would enjoy them too.
@Kevin: Nice to hear that! I hope you learn more stuff in the next installments of the series. :D
@Martin: Nice catch! I edited the article to fix the error, so thanks! Sorry about the rendering issue—I’m patching up the commenting system to fix the weird h2 rendering. :)
Aaron Newton
Again, excellent work! I need to update the mootorial list of links to include these excellent articles. Keep it up!
Pedro Visintin
Excellent article, this kind of articles are very important to show how good mootool is. Thanks for your work!
Jon Bomgardner
I tried to read through this tutorial but I couldn’t see any of the Javascript examples. I’m using Firefox 3.0.11 if it makes a diference. If you’d like screen shots or more information drop me an email.
Jon Bomgardner
Nevermind on the last comment.. looks like Firebug was causing the issue for some reason. When I turned it off and reloaded the page I could see everything. Not sure why it happened though………
Mark Obcena
@Aaron: Thanks for the links! :D
@Pedro: I’m glad you liked it. :)
@Jon: Yeah, I’ve been receiving several reports about the code blocks going blank in Firefox 3.0.11-12 (mostly on Linux but on Windows as well). I’m not sure what’s borking up the code highlighting (I’m using vanilla Lighter.js with a custom theme), but thank you about the firebug hint. I’ll try and see what’s causing the issue.
Anton
Keep up the great work, I’m really enjoying your series so far! I think I understand both the ‘Implement’ and ‘Extend’ methods but I don’t understand when I would use each one. I may be missing a trick here (excuse my lack of JavaScript knowledge) but wouldn’t it be better to not have a barrier between the methods? Would that be possible?
Ruud
Another way to create a singleton is implementing Class.Occlude. More one this you can read on Aaron’s blog http://www.clientcide.com/best-practices/using-classocclude-to-create-singletons/
Luis Merino
Cool work, I love the fact that nobody digs so elegantly into the core stuff, keep it up.
Diego Massanti
Very good article Markeeto! thanks!
Eneko Alonso
Hi there,
I just found about the article and, although I think it is a very good post, I am disappointed reading that new new is a hack.
If this syntax is correct: var MyClass = new Class({ … }); var MyInstance = new MyClass();
Then, removing the MyClass variable from the code should not be considered as bad syntax or a hack.
var MyInstance = new (new MyClass({ … }))();
The only difference between this code and the previous code is that we are eliminating the reference variable to the class itself.
If that is a hack, then I would say all anonymous functions that we declare all over the place without assigning them to a variable should be considered a hack too.
Other than that, as I said, the article is excellent and very helpful! Good job!
Eneko Alonso
By the way, not to say anything bad about Class.Oclude, but I would consider a hack using it for creating singletons, since it relays on a existing dom element.
JS architecture must be independent from the DOM.
Eneko Alonso
Ok, so thinking more productive, I have created Class.Singleton: http://github.com/eneko/Class.Singleton
Now we can create singletons the Mootools way :)
Mark Obcena
@Eneko: I’ve already written my reasoning about Singletons above, refer to it if you didn’t see it.
The reason why I’m adamant about using simple objects for singletons is because first, it’s easier and cleaner and second because it’s cheaper.
Everytime you call on the
newoperator, it creates a new object which is reference as thethisinside your classes. Yes, it creates a whole new object. Which means that you’re wasting object allocation during runtime that you could avoid by just using a simple object.Why do you want singletons in the first place? Because we want a single object. So why should we spend our time crafting a class that would only be used once? If you’re just gonna create an object in the first place, why even bother creating the object creator? That’s like saying, “Hmm, I want a sandwich—I think I’m gonna build myself a sandwich factory to create me a single sandwich.” Nice right? Or better yet—just create the sandwich.
Now that you understand, let me rebut your points:
The reason why we have classes in the first place is for reusable code. If you’re gonna create a class that you’ll just use once to create a single object, its reusability ceases to exist because it becomes a factory for a single need—which is why we want to eliminate the middle man by creating the end product itself rather than spend time building the factory.
This logic is fundamentally flawed because you don’t take into account the reason why we create variables in the first place—to hold values so we can reference them later. We don’t create variables out of whim.
It’s the same reason why we store our classes in variables—in order for us to have a way to reference them for later use. If we store a class in a variable, it means that there’s a distinct possibility that we may use it later and in multiple places, so we make sure that we have access to it. The only reason why’d we want to not keep our class in a variable is if we’re just gonna use it once. But if we’re just gonna use a class once—and only for creating a single object—isn’t it better if we just actually create the object itself using a literal? Why expend effort and additional runtime performance when we could just define it without having to go through the processing taken by class? And if you’ll look at how the
Classconstructor works, you’ll see that it does a lot of processing (and I mean a lot)—which we can shave off during runtime if we just use literals.I’ll assume that when you say “anonymous functions,” you’re talking about
(function(){...})(). First, they’re there because we want closures. Now if you look closely, you’ll see a()at the end. That’s called the function invocation operator. And you know why those anonymous functions have that operator in the end? That’s right: because we want them to run as soon as possible—and only run once. We don’t reference them because we don’t need them in the future—as soon as they’re done, that’s that. It’s finished.As with using object literals for singletons, we use actual function literals because we only need them once. There’s no magic anonymous function generator, no special constructors for anonymous functions. It’s just like what I said about singletons: ditch the factory-building process and just build the product.
This is the only thing I agree with in your comments. And I don’t really care about
Class.Occlude, which is why I didn’t write about it.I don’t wanna be harsh, but you just made a kitten cry. You created a class that creates a class that creates a single object. And MooToolsian, that is not. I think my toenail is more MooToolsian than that. Sorry. T_T
And now I should sleep.
Leena Levashvili
Thank you for the wonderful article that clarified many things in my mind.
One point that I can’t understand, though, is the following: “You might notice that we use $extend inside the function because this.implement wouldn’t be available inside the constructor function”.
I can’t wrap my mind around why it wouldn’t be available. After we invoke new Class to create Secretive constructor (var Secretive = new Class(funcInitialize); ), Secretive.prototype inherits from Class.prototype. When we invoke new Secretive to create an instance of class Secretive, a new Object is created that inherits from Secretive.prototype. This object is referenced by the this keyword. So, it seems, that when we reference this.implement inside the Secretive constructor, the js engine will look up the prototype chain and find Class.prototype.implement and call that. What am I missing here?
Also, in the same example, wouldn’t the getSecret and setSecret methods be created for each instance of Secretive instead of being shared by all instances via being created as methods of Secretive.prototype? Isn’t that something we want to avoid?
Thank you, Leena
Mark Obcena
@Leena: Here are the answers to your questions:
First, don’t get confused: an instance of a class (eg, an object created using
new X()) never inherits from theClassconstructor—otherwise, it would also be a class. The class itself isn’t the object—it’s simply a blueprint for the object. The methods of a class object therefore are not inherited by its instances; thus, we don’t have animplementmethod for instances, only the class objects themselves.It’s easier to look at this from the viewpoint of another language where classes are objects, for instance Ruby. A Ruby class is an object that inherits from the
Classclass. Say we have a ruby classX.X.allocateis a function, which it inherits from theClassclass, sinceXis a class object that is an instance ofClassclass. If we instantiate a new object,y = X.new,y.allocatewill be non-existent, becauseydoes not inherit fromClassclass—it only inherits fromX. The instance of a class and the class itself are separate objects: just because an object inherits from a class, and a class inherits fromClass, it doesn’t necessarily follow that the object inherits fromClass.On a related note, class objects created via the MooTools class constructor do not inherit from
Class.prototype, or to put it in code terms,(new Class() instanceof Class) === false. Of course, this does not affect anything, nor will anything be different if instance do inherit fromClass, because objects do not inherit from the constructor directly, but viaprototype. Otherwise, everything will have function methods.As for your other questions, the answer is yes: it does create methods for each instance. It’s not necessarily bad, as long as you do not need to change the method at runtime across all instances—which, from experience, is hardly ever needed.
Post a Reaction