Confusing constructors

Fraggle Rock’s doozers were pretty good at constructing objects

I tell you what I don’t like, I don’t like having to remember trivial details when programming. Having to recall the order my values need to be in when creating an object can be a pain in the brain, literally. In this episode of JavaScript Ice Cream I’m going to serve up a dollop of medicine, one that will mean you don’t have to deal with confusing constructors.

Let’s make a virtual gherkin

//Constructor
function Gherkin(size, colour, origin) {
this.size = size;
this.colour = colour;
this.origin = origin;
}
//Create new instance
var myGherkin = new Gherkin('large', 'green', 'my garden');
myGherkin.colour;
> "green"

So far so good. However, in a large application I might forget the required order of arguments that my constructor accepts as demonstrated below.

//Constructor
function Gherkin(size, colour, origin) {
this.size = size;
this.colour = colour;
this.origin = origin;
}
//...later on in my application...
//Create new instance
var myGherkin = new Gherkin('yellow', 'small', 'my garden');
myGherkin.colour;
> "small"

Oh dear. Now myGherkin’s colour property is set incorrectly :[

One way to deal with this issue is to rejig the constructor so that we can’t go wrong so easily. Let’s use just one argument, an object, rather than a series of strings.

//Constructor
function Gherkin(gherkinObj) {
this.size = gherkinObj.size;
this.colour = gherkinObj.colour;
this.origin = gherkinObj.origin;
}

Now we can safely construct a new object like so:

var myGherkin = new Gherkin({
size: 'large',
colour:'green',
origin:'my garden'
});
myGherkin.colour;
> "green"

As you can see, it’s crystal clear what’s being fed in to our constructor and it doesn’t matter what order the properties are in. We’ve sacrificed a little brevity for a lot of clarity and importantly some safety.

Avoiding slip ups

We have a nice approach to our problem, but we don’t get any errors if we pass in an object which has different properties than the one in our constructor. We can fix this by creating a utility function that outputs a console message when that’s the case:

function constructorChecker(argObj, thisObj) {
var uniqueProperties = [];
  //store object properties in an array
for (var i in argObj) {
uniqueProperties.push(i);
}
  //loop through the constructor object and array
//remove items that match
for (var j in thisObj) {
for (var k = 0; k < uniqueProperties.length; k++) {
if (j === uniqueProperties[k]) {
uniqueProperties.splice(k, 1);
}
}
}
  //Show message if there's unmatched items
if (uniqueProperties.length > 0) {
console.log(‘you have unused properties: ‘, uniqueProperties);
return uniqueProperties;
}
}

Here we’re simply eliminating any properties which are common to both objects and displaying a message in the console if there’s anything left over. This function can be used like so:

//Constructor
function Gherkin(gherkinObj) {
this.size = gherkinObj.size;
this.colour = gherkinObj.colour;
this.origin = gherkinObj.origin;
var thisObj = this;
 //Call our checker function
//passing in the two objects
constructorChecker(gherkinObj, thisObj);
}

Now we’ll get a friendly warning if we’re attempting to create an object with properties that do not exist.

A full demo of this can be found on JSFiddle here.

If you have any nice techniques for handling similar situations please share your wisdom via the comments section.

Construct safely.