Factory pattern for a more robust constructor

A JavaScript constructor is just a simple function. It should be called through the "new" operator so that it would provide its added value of setting "this" to refer to the newly created object, inheriting from the function prototype, and returning a reference to "this" object. But what if a client programmer mistakes the sense of our construct, and calls it as a simple function?

Let's think what happens when the constructor I defined in the previous post is called directly:
function Rectangle(a, b) {
    this.a = a;
    this.b = b;
}

// ...

var rx = Rectangle(6, 7); // !! bad mistake !!
So, I forgot to use "new", and Rectangle is treated by JavaScript as a normal function call. What happens is barely that, in the global scope, two properties named a and b are created (if not already there) and set to 6 and 7. Then "undefined" is returned and assigned to the variable rx.

Is this what I really wanted to happen? Hardly so. And even in that case, I should have used a different function to make clear that it was intentional, and not a silly mistake.

I can think to a couple of ways to improve my code: signaling the user programmer that he is doing something unexpected, or silently transform his mistake in the right thing. In the first case I would typically throw an exception, in the second one I would use the factory pattern.

Throwing an exception

This is the most clean but unforgiving solution. To implement it, we check "this" in our constructor function. If it is not associated to the instance of the function, it means that the user didn't call it properly. So we raise an exception, and the let the user programmer the burden to deal with it.
function Rectangle(a, b) {
    if(!(this instanceof Rectangle))
        throw 'Remember to use "new" to call a constructor!';
    
    this.a = a;
    this.b = b;
}

// ...

try {
    var rx = Rectangle(3, 4);
}
catch(e) {
    console.log(e);
}
As I said, this is clean code, and if you have a background in languages supporting static type, you should appreciate the predictability of what it is going on here. The caller does something wrong, he gets a rigorous "no, no" back.

Still, it doesn't looks right to me, when compared to the normal JavaScript behavior.

Factory pattern

Less clean, more forgiving. If someone calls a constructor as a simple function, we patch his code on the fly, converting it to a proper constructor call. The user programmer could now create a new Rectangle calling the constructor as was originally expected, or as a normal function:
function Rectangle(a, b) {
    if(!(this instanceof Rectangle))
        return new Rectangle();

    this.a = a;
    this.b = b;
}

// ...

var rf = Rectangle(12, 2);
// ...
Your choice

I feel that using the factory pattern is more in the JavaScript way of writing code, but I guess this is a matter of which kind of application you are developing, team programming conventions, and the such.

In any case, I would suggest you to choose one of the two approaches (or three, if you think that, after all, not checking is a viable option), and keep it in all your project.

No comments:

Post a Comment