0

A function I wrote takes an object as only argument, and naturally I need this object to follow a particular object specification (what properties it has, of what type, etc.).

Instead of passing it as an object literal and do all the checking within the function, I had the idea to write a "constructor" function to which you pass that literal object, and that does all the job of enforcing the object specification, plus providing default values if necessary.

This function won't be called with new because it has no need for prototypal inheritance. The return object may include a special property (_isAPoint in the example) to "prove" that the object was properly constructed (a replacement for instanceof).

I don't remember having seen this kind of approach before. At first sight, it seems a clean way to create valid argument objects, while avoiding the whole mechanism of prototypal inheritance.

What do you think? Is this an identified pattern? Could you point me to possible drawbacks and improvements?

Simplified example:

var Point = function (opts) {
    "use strict";
    var defaults = {
        color: "blue",
        x: 0
    };

    opts = $.extend(defaults, opts); // (using jQuery's extend)

    if (!isNan x) {
        throw new Error("x must be a number");
    }

    return {
        _isAPoint: true,
        color: opts.color,
        x: opts.x
    };
};

Called like this:

someNiceMap.addPoint(Point({ x: 2, color: "red" });
someNiceMap.addPoint(Point({ x: 14 });
  • 1
    Looks fine. You could pass an object to addPoint and put the checking code in there. Passing objects to function is a good idea when inheriting and extending for an example of that check here. http://stackoverflow.com/a/16063711/1641941 but the way you implement it works fine too. – HMR Feb 17 '14 at 10:44
  • 1
    One thing I may warn about is that Point (upper case) would suggest a constructor function to some programmers. The convention is that functions starting with an upper case are constructors and can be invoked with new. In your case it actually will return the same object whether you call it with new or not but since it's not a constructor function it may be better not to name it Point (capital P). – HMR Feb 17 '14 at 13:59
  • @HMR: My starting point was indeed to create a fully-fledged "constructed" object (using `new`), which explains the capital. Now I'm aware of the fact that my function is not a constructor (in the strict sense), and of course you're right about the capital P. The title of my question was misleading too, I edit it slightly. – Nicolas Le Thierry d'Ennequin Feb 17 '14 at 16:28

1 Answers1

1

What you show is called a Factory Method Pattern.

There is no fundamental flaw in this approach and it is considered an alternative to the constructor pattern.

Pros and cons of both approaches are presented in this blog entry by Eric Elliot:

http://ericleads.com/2013/01/javascript-constructor-functions-vs-factory-functions/

As you can see the only important drawback is the inability to use this to refer to the newly created object.

But is it a drawback? Be warned that Eric is known for being against constructor function in favor of factory methods.

To make your code cleaner, make the factory method explicit:

var point = {

   create : function( opts ) { 
      ...
      return {
        _isAPoint: true,
        color: opts.color,
        x: opts.x
      };
   }
}

The call is now cleaner:

someNiceMap.addPoint( point.create( ... ) );
Wiktor Zychla
  • 47,367
  • 6
  • 74
  • 106