1

Lets say we have the code:

var MyConstructor = (function() {
  var constructor = function(name, type) {
    this.name = name;
    this.type = type;
  };

  constructor.prototype: {
    init: function() {
      console.log(this.name);
      console.log(this.type);
    },
    errors: {
      message: function() {
        return "error";
      },
      presence: function() {
        // how do I access the each method off of the prototype in a clean manner?
        ?.each(function() {
          console.log('iteration');
        }); 
      }
    },
    each: function(cb) {
      this.type.forEach(function(t) {
        cb();
      });
    };
  };

  return {
    constructor: constructor
  };
}); 

I have a constructor with some methods, but also has an object errors with methods belonging to that object. How does errors access the constructor's methods?

Seth
  • 10,198
  • 10
  • 45
  • 68
  • Depends on how you call `presence`. You probably have to create/bind the function. For each instance in the constructor. – Felix Kling Mar 26 '14 at 16:41

2 Answers2

1

There is no way for the errors object to know its "parent" directly. It's a different object, and technically you could grab a reference to it and make it a property of some other object.

There are a few ways to approach a solution.

You could move the declaration of errors into the constructor function and use a closure to keep a reference to the parent. This way errors is still a distinct object that you can reference. You just can't use prototype because you need the closure scope.

var constructor = function(name, type) {
  var errorParent = this;
  this.name = name;
  this.type = type;
  this.errors = {
    message: function() {
      return "error";
    },
    presence: function() {
      // access the parent's each() method
      errorParent.each(function() {
        console.log('iteration');
      }); 
    }
  },
};

A second alternative would be to make the message and presence methods become members of the constructor's prototype. Now you can keep the prototype structure, but there is no errors object.

constructor.prototype: {
  init: function() {
    console.log(this.name);
    console.log(this.type);
  },
  errors_message: function() {
      return "error";
  },
  errors_presence: function() {
      this.each(function() {
        console.log('iteration');
      }); 
  },
  each: function(cb) {
    this.type.forEach(function(t) {
      cb();
    });
  };
};

A third alternative is to make Errors an entirely separate class and create an instance errors within your constructor. Then the errors object would have an explicit reference to the object it is responsible for managing.

var constructor = function(name, type) {
  this.name = name;
  this.type = type;
  this.errors = new Errors(this);
};

...and elsewhere in the code...

function Errors(object) {
  this.object = object;
};
Errors.prototype.message = function() {
  return "error";
};
Errors.prototype.presence = function() {
  this.object.each(function() {
    console.log('iteration');
  }; 
};

The third approach seems the cleanest to me, but you'll have to decide which approach fits your application best.

P.S. As an aside, I know JavaScript object literals are all the rage for declaring entire classes, but many times (as in this case) using them actually restricts the way developers think about the code instead of enlightening them. IMHO.

Lee Jenkins
  • 2,299
  • 3
  • 24
  • 39
  • Thanks for the elaborate answer. I was looking for a way without changing my code, but the more and more I read, creating a class out of errors seems to be the cleanest way to do it for what I need. I'm not bound to literals, just needed a namespaced way of going about my errors. The last example does what I was as well as reading up on this answer http://stackoverflow.com/questions/15884096/organize-prototype-javascript-while-perserving-object-reference-and-inheritance. – Seth Mar 26 '14 at 20:03
  • 1
    You are welcome, and thank you for accepting the answer. It would benefit me (and others too!) if you up-vote the answer as well. Thanks! – Lee Jenkins Mar 26 '14 at 20:19
0

You could bind the method so this will always be a reference to the constructor, not to the caller.

var MyConstructor = (function() {
  var constructor = function(name, type) {
    this.name = name;
    this.type = type;
  };

  constructor.prototype: {
    errors: {
      presence: (function() {
        // this is the constructor.
        this.each(function() {
          console.log('iteration');
        }); 
      }).bind(this)
    }
  };

  return {
    constructor: constructor
  };
}); 
000
  • 26,951
  • 10
  • 71
  • 101
  • I `console.log(this)` in `presence` and get window, any idea why? Shouldn't it be `constructor`? – Seth Mar 26 '14 at 16:58
  • Try `.bind(constructor)` rather than `.bind(this)`. – 000 Mar 26 '14 at 16:59
  • You want to bind to an instance, don't you? That will never be available on the prototype, see https://stackoverflow.com/questions/16502467/prototype-deep-scope-of-this-to-access-instances-scope?lq=1 – Bergi Mar 26 '14 at 17:00
  • Oh dang, I need to read up more. – 000 Mar 26 '14 at 17:05