OOP in JavaScript - Part 4: Scoping

Permanent Link: OOP in JavaScript - Part 4: Scoping 21. Dezember 2009 Comment No Comment

I agree, it took me a while to write part 4 of my OOP in JavaScript series, but here it is now. As for the whole series, basic JavaScript knowledge is needed.

Scoping together with OOP is always an issue, when using asynchronous calls combined with callbacks. Let's create a very easy example where one method of a class registers an onclick EventListener and the second method of the class is the callback for the EventListener. The second method simply calls an alert with a message text defined in the class. Note that the Event Listener registration is not cross-browser safe:

function Handler()
{
}

Handler.prototype.messageText = 'You have clicked somewhere in the document';

Handler.prototype.registerAll = function()
{
window.addEventListener('click', this.handleOnclick, true);
}

Handler.prototype.handleOnclick = function(event)
{
alert(this.messageText);
}

var handler = new Handler();
handler.registerAll();

When clicking anywhere in the document you'd be expecting to see a message box "You have clicked somewhere in the document", but you only get a mesage box saying "undefined". Why is that?

The second argument of addEventListener() is the callback, it expects a function. By putting this.handleOnclick as callback, you are passing a copy of that function. It would be same if you had written it like this:

window.addEventListener('click', function() { alert(this.messageText); }, true);

As you can clearly see now the function stands for itself, this is not in the context(=scope) of the class Handler. In order to achieve exactly that, JavaScript gives us 2 possibilities: apply() and call(). Basically they are both the same, the only difference is in the way you pass further arguments. For a closer distinction, take a look at this page.

By passing an instance as first argument we are telling the function that is called in which scope to be executed, meaning: What instance is this? Let's alter the registerAll method of the example:

Handler.prototype.registerAll = function()
{
window.addEventListener('click', this.handleOnclick.apply(this), true);
}

When running your page now, you will notice that the alert puts out the right message, but is called the moment your page is rendered and the onclick event doesn't work anymore. This is because apply() and call() directly call the respecting function.

What we need to do, is to dynamically create a function that is called with the right scope when needed.

function Handler()
{
}

Handler.prototype.messageText = 'You have clicked somewhere in the document';

Handler.prototype.registerAll = function()
{
window.addEventListener('click', this.createOnclickHandler(), true);
}

Handler.prototype.createOnclickHandler = function()
{
var myScope = this;
return function(event) {
var handle = function(event) {
alert(this.messageText);
}
handle.call(myScope, event);
}
}

var handler = new Handler();
handler.registerAll();

Finally we get to see a "You have clicked somewhere in the document" message box only when clicking somwhere in the document. Note that the second parameter of call() is the Event Object, which is passed as first argument to the called function.

If using this is not total must for you, you can also throw away one of the functions and simply use myScope instead of this:

Handler.prototype.createOnclickHandler = function()
{
var myScope = this;
return function(event) {
alert(myScope.messageText);
}
}

OOP in JavaScript - Part 3: Extending classes

Permanent Link: OOP in JavaScript - Part 3: Extending classes 22. September 2009 Comment No Comment

After I've already covered normal and static classes, Part 3 is about extending classes. As before, basic knowledge in OOP and JavaScript is needed.

First, let's create a class Human with setters and getters for the age:

function Human()
{

}

Human.prototype._age = 0;

Human.prototype.setAge = function(age)
{
if (typeof age != 'number') {
throw('Invalid Age provided');
}
this._age = age;
};

Human.prototype.getAge = function()
{
return this._age;
};

Since there are no keywords like class, private, public or protected in Javascript it's no surprise there's no keyword extends aswell. In order to extend a class you have to use prototyping:

function Woman(age)
{
    this.setAge(age);
}

Woman.prototype = new Human();

Now we've created a new class Woman that inherits all methods and properties from Human by assigning Woman's prototype to new Human(). To show it's easily possible, I've also changed the constructor as it now takes age as parameter. Creating a new object Woman and reading the age looks like this:

var woman = new Woman(22);
alert(woman.getAge());

You can overload methods simply by redifining them. In this case we'll overload the getAge method where we'll add an additional check and then call the parent getAge method. Since you actually don't call the parent method but call the parent method in static way, it is important to add call(this) in order to call the method in the actual context.

Woman.prototype.getAge = function()
{
if (this._age > 100) {
throw('This person is probably already dead!');
}
return Human.prototype.getAge.call(this);
};

Multiple inheritance is possible, but not very easy. For a method using Swiss Inheritance, check this page. Extending static classes might be possible, but I don't know a way. Problem is you need to clone the parent class (which is not that easy in JavaScript), if you write it like this the child becomes the parent and the other way round, meaning if you add a method in the Child it is also available in the parent:

function Cookie()
{

}

Cookie.get = function()
{
return 'something';
};

var CookieChild = Cookie;
alert(CookieChild.get());

Part 4 (probably the last one of the series for now) will cover scoping.

OOP in JavaScript - Part 2: Static classes and Singleton

Permanent Link: OOP in JavaScript - Part 2: Static classes and Singleton 15. September 2009 Comment No Comment

After I've covered normal classes in Part 1 of the series, the second part will focus on static classes and singletons. As before basic OOP and JavaScript knowledge is needed.

Generally writing and using static classes is monstly the same as normal classes. The difference is that you don't need to instantiate the object with new and you can't use prototyping nor this, since everything is in static context. One useful implementation for static classes is the Registry Design Pattern. First off we create the class with a property to store the registry values in afterwards:

function Registry()
{
}

Registry._data = {};

Right now, I can't really do a lot with this class, that's why I'll create a static method that allows me to set key-value-combinations:

Registry.set = function(key, value) {
Registry._data[key] = value;
}

Now I'm able to register stuff in the registry. Since I don't need an instance of the class I can call my method directly:

Registry.set('userIsAuthorized', false);

I'll leave out the getter you'd still need for a useful registry.

If you want to prevent anyone from writing new Registry() you only have to throw an exception in the constructor:

function Registry()
{
throw('You cannot instantiate Registry');
}

Maybe for some reason you wanna use Registry as a singleton. In that case you have to combine normal class methods and properties with static ones. You write the Registry as a normal class and implement one static property instance and one static method getInstance. The Registry class would then look like this:

function Registry()
{
}

Registry.instance = null;

Registry.getInstance = function() {
if (Registry.instance === null) {
Registry.instance = new Registry();
}
return Registry.instance;
}

Registry.prototype._data = {};

Registry.prototype.set = function(key, value) {
this._data[key] = value;
}

Since JavaScript doesn't have access modifiers like private, public or protected I had to remove the exception from the constructor. You could do it with a randomly generated token passed to the constructor, but this method is not bulletproof like any other I can think of.

In part 3 (that'll come later this week) I will write about extending classes.

OOP in JavaScript - Part 1: Writing classes

Permanent Link: OOP in JavaScript - Part 1: Writing classes 12. September 2009 Comment No Comment

OOP in JavaScript works a bit different than known from other languages. That's why I decided to do a series of "OOP in JavaScript" blogposts, where I want to show how OOP in JavaScript works. The series will discuss topics like creating classes, prototyping, extending classes, static classes, scoping, and so on. To understand these postings a basic knowledge of JavaScript and OOP is needed. This first part is about creating classes/prototyping.

First thing you need to know: There is now keyword class in JavaScript. In order to create a class in JavaScript, all you have to do is to create a function and then create a new class instance by using the known keyword new:

function Product() {}

var product = new Product();

The function we've created is the constructor of our new class. To create methods and properties there are two ways: You can either declare them in the constructor or you can do prototyping.

Declaring it in the constructor:

function Product() {
this.id = 71288;

this.getId = function() {
return this.id;
}
}

Prototyping:

function Product() {}

Product.prototype.id = 71288;

Product.prototype.getId = function() {
return this.id;
}

Personally I prefer prototyping as it is more clear. If you want to call the function getId() it always works the same way with both methods:

var product = new Product();
alert(product.getId());

This class is still quite static, since the id is hardcoded in it. To make it dynamic I just need to modify the constructor to make it accept a config object. Notice that I replaced the id property with a config property that stores the whole config given to the object.

function Product(config) {
this.parseConfig(config);
}

Product.prototype.config = {};

Product.prototype.parseConfig = function(config) {
if (typeof config != 'object') {
throw('Parameter "config" must be of type object');
}
// ID should always be set and a number
if (typeof config.id != 'number') {
throw('Config Parameter config.id must be a number');
}
this.config = config;
}

Product.prototype.getId = function() {
return this.config.id;
}

As you can see I also already implemented checks that the config must always be an object and that an id must always be set and a number. Creating a new instance of the class now looks like this:

var product = new Product({
id: 71288
});

This way we can now dynamically create Product Objects based on Product IDs we read from e.g. a database.

In the second part, that will come within the next few days I will write about static classes.

Unit Tests: How to test for Exceptions

Permanent Link: Unit Tests: How to test for Exceptions 3. April 2009 Comment No Comment

When unit testing, you'd also want to test whether your application throws Exceptions as expected (the following examples are based on SimpleTest). Assumption for the examples is, that we have a method that expects an integer as parameter.

First way you probably come up with is this:

try {
$class->method('abc');
} catch(Exception $e) {
$this->assertIsA('Exception', $e);
}

Generally this looks ok, but it's not. If the method doesn't throw an exception, the test won't fail since the catch block is never executed. That's why we simply drag the test out of the catch block:

try {
$class->method('abc');
} catch(Exception $e) {
}
$this->assertIsA('Exception', $e);
unset($e);

Now the test fails when the exception isn't thrown because first of all $e won't be set and will surely not be an exception. It is important to add an unset($e), especially if you're testing for more exceptions directly afterwards.

Let's now assume that the method throws an InvalidArgumentException if the given parameter is not an integer.

try {
$class->method('abc');
} catch(Exception $e) {
}
$this->assertIsA('InvalidArgumentException', $e);
unset($e);

Now the test is in a state where it fails when no exception is thrown or when the thrown exception is not an InvalidArgumentException.

In case you're not lazy on typing, you might add one more line, which also allows you to put the assert back into the catch block:

try {
$class->method('abc');
$this->fail('Excepted exception was not thrown');
} catch(Exception $e) {
$this->assertIsA('InvalidArgumentException', $e);
unset($e);
}
		
		

Zend Framework: Generating URLs from defined routes

Permanent Link: Zend Framework: Generating URLs from defined routes 23. Februar 2009 Comment Comments (2)

The Zend Controller Router allows you to easily create your own routes. That is very useful, but it seems rather unknown, that you can also use these routes to generate URLs according to their definition.

Let's assume you have a route like this:

$controller = Zend_Controller_Front::getInstance();
$router = $controller->getRouter();

$productRoute = new Zend_Controller_Router_Route(
':pid/:name',
array(
'module' => 'default',
'controller' => 'product',
'action' => 'show'
),
array(
'pid' => '\d+'
)
);
$router->addRoute('productpage', $productRoute);

In this route we parse a URL that is supposed to show a product page. The URL will look like http://www.phpdevblog.net/4815162342/Microsoft+Windows+XP+Professional for example. The Router would explode it into pid=4815162342 and name="Microsoft Windows XP Professional"

To generate a URL with the help of the Router you simply need to call the assemble method, which you can either call from the router or the definied route, but keep in mind that you will get different results!

From the router the assemble would look like this:

$link = $router->assemble(
array(
'pid' => '4815162342',
'name' => 'Microsoft Windows XP Professional'
),
'productpage'
);

The result of this method is /4815162342/Microsoft+Windows+XP+Professional

The only difference, if you call the assemble method from the defined route, is that you don't need the route name in the second parameter:

$link = $productRoute->assemble(
array(
'pid' => '4815162342',
'name' => 'Microsoft Windows XP Professional'
)
);

Here the result is 4815162342/Microsoft Windows XP Professional

Extending interfaces

Permanent Link: Extending interfaces 21. Januar 2009 Comment No Comment

What many people don't know is that you cannot only extend classes in PHP but also interfaces:

interface First_Interface
{
public function show();
}

interface Second_Interface extends First_Interface
{
public function update();
}

class Product implements Second_Interface
{
public function show() {}
public function update() {}
}

You have to remember though that extending is not possible when you have the same function in both interfaces:

interface Second_Interface extends First_Interface
{
    public function show();
    public function update();
}

This will lead to a PHP Fatal Error:
PHP Fatal error:  Can't inherit abstract function First_Interface::show() (previously declared abstract in Second_Interface) in /tmp/interfaces.php on line 8

Fatal error: Can't inherit abstract function First_Interface::show() (previously declared abstract in Second_Interface) in /tmp/interfaces.php on line 8

Note: This possibility is also described in the PHP documentation for interfaces (Example #3)