Hari Seldon
Hari Seldon

Reputation: 1060

Cannot see properties added to prototype from child object

I need some help understanding how javascript protoypal inheritance works... or rather why its not doing what I am expecting it to do.

Essentially I am trying to establish templated objects that are returned from a new statement. I have a generic constructor function in a utils.js module that assigns any values from a parameter object to a corresponding template object, I return that modified template object as a result of invoking new.


module.exports.ctor = ctor;

//Mapped object constructor
function ctor(template) {

  return function(args) {
     var s, t, p;

    //guard against being used without new
    //courtesy of John Resig http://ejohn.org/blog/simple-class-instantiation/
    if (!(this instanceof arguments.callee)) {
      throw new Error("Constructor called without 'new'");
    }

    //create a deep copy of `template` to modify
    t = JSON.parse(JSON.stringify(template));
    args = args === 'undefined' ? {} : args;   

    // copy values of matching properties from `args` to `t`
    // (uses Crockford's `typeOf` function http://javascript.crockford.com/remedial.html)
    for (p in t) {
      if (args[p]) {
        s = typeOf(t[p]);

        if (s === 'function' || s === 'null') {
          /* do nothing */
        } else if (s === 'array') {
          t[p] = t[p].concat(args[p]);
        } else {
          t[p] = args[p];
        }
      }
    }

    return t;
  };
}

Here is an example of how the generic constructor would work on a Contact template object, with some Contact specific properties added to the prototype object:

var template = {
    email: null,
    phone: null,
    address: []
};

var Contact = require('../util').ctor(template);

Contact.prototype.template = template;

Contact.prototype.print = function() {
  var str = this.email + '\n';
  str += this.phone + '\n';
  for (var i = 0; i < this.address.length; i++) {
    str += this.address[i].toString() + '\n';
  }
};

module.exports = Contact;

My expectation is that the template property and the print function would be available in the returned object's chain, however it appears that they are not (from node REPL):

> var Contact = require('./mapping/Contact');
undefined
> var c = new Contact();
undefined
> c.print
undefined
> c.template
undefined
> c
{ email: '', phone: '', address: [] }

Can someone explain to me why if I am explicitly adding properties to the prototype of Contact, those properties are not available to the returned object?

Upvotes: 1

Views: 128

Answers (1)

gilly3
gilly3

Reputation: 91497

This is because ctor() causes the constructor to return t, which is a plain generic object. Since the constructor is returning the plain object, you lose the prototype. Instead of returning t, copy the properties of t to this:

for (var k in t) {
    this[k] = t[k];
}

Then, don't return anything. Or, return this, if you prefer.

Upvotes: 2

Related Questions