Object Oriented Javascript and OO JS Callbacks
Why don't you subscribe to my blog while you're here? I'm a freelance web developer and I blog about Ruby, Rails, and business online.
Go ahead and subscribe to my RSS feed. Thanks for visiting!
Here’s an Object Oriented Javascript tutorial.
Here’s the source code for the tutorial being executed so you can follow along if you like. To grab the source just view the source of that page.
I had never _really_ touched Javascript until a couple of months ago when I realised I had to get serious and learn it. I am very glad I made that move. Javascript is pretty nifty, but when you start to work with it at first it’s hard to take seriously. For example, my 700 page long Javascript book dedicates 26 pages to Object Orientation, but if you’re building anything substantial in JS you will want to use OO techniques. Here’s a quick JS OO primer (mind you, I’m no JS guru) and some info on Javascript callbacks in the OO world. This will be particularly helpful to those jumping on the AJAX wave and integrating with “Prototype”:http://prototype.conio.net/.
OO JS seems to go against the current JS usage trend. As I quickly discovered, OO JS can be confusing, messy, and tricky. OO JS uses a “quirky” prototype style method to define your classes, and methods. I say quirky because no doubt this style has been discussed thoroughly in academic circles, but for you’re typical developer coming from a C++/Java background it can be daunting. Lets define a person class:
/*************************************************************
Person
*************************************************************/
//You don't need to define class variables but it's
//good practice for neatness sake.
Person.prototype.name = null;
function Person(name) {
this.name = name;
}
Person.prototype.talk = function() {
document.write("Hi! My name is "+this.name+"
");
}
Person.prototype.setName = function(name) {
this.name = name;
}
And then use it:
person = new Person('alex');
person.talk(); // Hi! My name is alex
document.write(person.name+"
"); // alex
//Alex moves to Italy...
person.setName('alexio')
person.talk(); // Hi! My name is alexio
“That’s whack”, I hear you say. That’s exactly what I thought! You kind of have to think outside the class paradigm because they are “theoretically different paradigms”:http://en.wikipedia.org/wiki/Prototype-based_programming. In OO JS “prototype” is a special object that defines the entity. You can hang stuff off the prototype including methods (Person.prototype.talk) and properties/class variables (Person.prototype.name). When ever you try to use a method of property of an object, the language will refer to the prototype to work out what you want to do.
Fundemental to OO is inheritance. Here’s Employee inherting from Person, and we’re overriding the talk() prototype.
/*************************************************************
Employee
*************************************************************/
function Employee() {}
//Employee is "extending" Person.
Employee.prototype = new Person();
Employee.prototype.vocabulary = new Array(
"Yes sir!",
"I agree whole heartedly and without dispute, sir.",
"Good one sir!",
"Anyone for coffee?",
"Anyone for water?",
"Home time!",
"Yeh, I'm still paying off my student loan.",
"*Sigh* Another monday."
);
//Employee is overriding the talk() method of Person.
Employee.prototype.talk = function()
{
saying = Math.round(Math.random() * (this.vocabulary.length-1) );
document.write(this.vocabulary[saying]+"
");
}
And again we then use the Employee prototype to create a real employee.
employee = new Employee(); employee.talk();<p>So we interhit the Person prototype by cloning an example of the prototype and calling it Employee. We then override the talk() method. That"s pretty much the basic OO functions covered. Now we get a little trickier. In the next example we"re going to create an UpperManagement prototype that will inherit from Person once again. The difference in this example is that we are going to dynamically modify the prototype instance so that instead of UpperManagement saying what they want, we tell them what to say.</p> <pre> /************************************************************* Upper Management *************************************************************/ function UpperManagement() {} UpperManagement.prototype = new Person('God'); UpperManagement.prototype.talk = function() { document.write("Don't worry, last years losses will be made up by this years projections.<br/>"); } your_boss = new UpperManagement(); your_boss.talk(); document.write(' <h1>Modified Upper Management</h1> '); //If only we could do this in real life. your_boss.talk = function() { document.write("Double salary for all!<br/>"); } your_boss.talk();
Cool huh? So initially we simply define UpperManagement and let them talk their gibberish. Then we redefine the way they talk to something we can stomach.
Now, for my final trick I will present a way to use a method from an object as a callback for another function. This is trickier than you may think!
Talk Oscar!</div> <div id="talking_advanced">Say Hello!</div> <script type="text/javascript"> /************************************************************* Person Callback *************************************************************/ //My dog Oscar may as well be human sometimes... myDog = new Person('Oscar'); myDog.talk = function() { placeholder = document.getElementById('talking'); placeholder.innerHTML += " ... woof! woof!<br/>"; } //Lets see if we can get him to talk after a 2 second pause. setTimeout(myDog.talk, 2000); //You should have seen the 'Talk Oscar!' text on the page change after two seconds. //Lets say we want him to say something really advanced. myDog.talk_advanced = function() { placeholder = document.getElementById('talking_advanced'); placeholder.innerHTML += " ... Hurro! ry rame is r"+this.name; } //Oops! This doesn't work! We set the callback of the timer to call a function //prototype the requires 'this' to be set. Unfortunately, because it's only a //prototype the request of 'this' will fail :( setTimeout(myDog.talk_advanced, 2000); //We need to create a function that knows the object at the time the callback is required. function FunctionInvoker(me) { this.me = me; this.invoke = function() { me.talk_advanced(); } } myDogTalking = new FunctionInvoker(myDog); setTimeout(myDogTalking.invoke, 5000); </script>Let me run through it briefly. FIrstly we create an instance of my Beagle called Oscar. He’s like a person sometimes so it’s OK if we clone the Person prototype. Next we get him to talk more dog like. Then we get him to talk after a two second pause, which works fine. Oscar is a smart dog and obedient at times, so I set a harder command for him where he has to say his name. The command requires Oscar to use his instance variable “this.name”. This wont work in the standard way because we simply “clone” the function prototype and use it as the callback function. The problem with this is that the function is no longer part of an instance. We require the assistance of an agent, FunctionInvoker. We tell FunctionInvoker the object we want to call, and we define a function (this.invoke =…) that acts as a proxy to the object’s method we really intend on calling.
That’s pretty hardcore and if you understood it then well done! If you didn’t then don’t worry. Trace it through and you’ll get it.
That’s a wrap for this tutorial. If there’s any mistakes or corrections required then please let me know by commenting to this post! Enjoy!
Leave a Reply

