I'm a big fan of the Factory/Constructor pattern in JavaScript.
function Foo() {
if (!(this instanceof Foo)) {
return new Foo();
}
// the rest of your initialization code
}
Foo.prototype = { ... };
var f1 = new Foo(), // f1 instanceof Foo === true
f2 = Foo(); // f2 instanceof Foo === true
But this runs into a problem when you want your constructor to accept any number of arguments.
Function Person(mother, father) {
this.mother = mother;
this.father = father;
this.children = [].slice.call(arguments,2);
}
Apply invocation vs Constructor invocation
Unfortunately, you would need to invoke the constructor via Person.apply(arguments) to pass all the arguments in individually, but that doesn't create an instance of Person since it wasn't called via new. You can get around this by referring to a local variable in your constructor that is either this or a new empty instance, then applying the changes to whatever is in the variable and returning it.
Function Person(mother, father) {
var self = (this instanceof Person) ? this : new Person();
self.mother = mother;
self.father = father;
self.children = [].slice.call(arguments,2);
return self; // important
}
When a constructor returns an object, the return statement is honored over the default behavior (sans return statement) of returning a class instance.
But this doesn't pan out if it is inappropriate for the class to be called without arguments or if there's some complex logic that needs the seed info in order to make sense.
Quite a list of requirements
Now, at this point any reasonable person would probably rethink the architecture that necessitated such a construct (seriously, is it really a requirement to also support function invocation?), but a) I'm not a reasonable person, and b) hey, fun with code! So here goes.
Circling back to the point that returning an object from a constructor will trump the default behavior, we can just defer the construction behavior to another constructor function.
function Person(mother, father) {
return new _Person(arguments);
}
function _Person(_) {
this.mother = _.shift();
this.father = _.shift();
this.children = _;
}
Now it doesn't matter how you execute the Person function. It will return an instance of _Person, which is set up with the initialization code in its constructor.
But I didn't ask for a _Person
Now there are two things left to attend to: 1) the returned object isn't an instance of Person, and 2) we now have two constructor functions exposed to our consumers.
var Person = (function () {
function C(mother, father) {
return new _Person(arguments);
}
function _Person(_) {
this.mother = _.shift();
this.father = _.shift();
this.children = _;
}
C.prototype = _Person.prototype = { ... };
return C;
})();
Assigning _Person's prototype to C (aka Person) makes instances pass the instanceof test and allows for modifying the class prototype with the expected outcome. And defining the helper constructor in a closure hides it from the implementation layer.
Overkill? Almost certainly. But JavaScript is a fun language, and who knows? Maybe this pattern is just the right thing for some use case out there. Ok, maybe not :)