0

I have two files: BaseController.js and EventRecordController.js. EventRecord needs to inherit a few methods from BaseController.

BaseController

var Q = require('q'),
    util = require('../util');

exports.BaseController = function(req, res) {
    this.req = res;
    this.res = res;
    this.fields = {};
    this.error = {
        code: 200,
        message: 'BAD REQUEST: The parameters provided were invalid. See response body for error messages.',
        specific_message: ''
    };
};

// Utility method to handle returning errors that are thrown.
exports.BaseController.prototype.handle_errors = function(error) {
    if(this.error.code === 500) {
        util.internal_error(this.res, this.response_type);
    } else {
        var response = util.build_error_response(this.response_type, this.error.code, this.error.message, this.error.specific_message);
        util.send_response(this.res, this.response_type, this.error.code, response);
    }
};

// Check to see if a user is authenticated and whether they are using a correct response type.
exports.BaseController.prototype.validate_response_type_and_authenticate = function() {
    var deferred = Q.defer();
    util.validate_response_type_and_authenticate(this.req, this.res, function(auth_data, response_type) {

        this.auth_data = auth_data;
        this.company_user_uid = this.auth_data.data.company.uid;
        this.response_type = response_type;
        this.v3_token = this.auth_data.data.token;

        deferred.resolve();
    });
    return deferred.promise;
};

EventRecordController

var base_controller = require("./BaseController"),
    Q = require('q'),
    util = require('../util'),
    validator = require('validator');


exports.EventRecordController = function(req, res) {

    function EventRecord(req, res) {
        base_controller.BaseController.apply(this, arguments);
    }

    // Inherit from BaseController, then fix constructor.
    EventRecord.prototype = new base_controller.BaseController();
    EventRecord.prototype.constructor = EventRecord;

    EventRecord.run = function() {
        console.log(this.error);
    };

    return EventRecord;
};

When I run the following code, this.error logs as undefined from within the run() method.

var event_record_controller = require("./controllers/EventRecordController"),
    util = require('./util'),
    validator = require('validator');

exports.record = function(req, res) {
    var controller = new event_record_controller.EventRecordController(req, res);
    controller.run();
};

I think I'm missing something obvious here, but my experience with prototype based inheritance is limited.

Jack Slingerland
  • 2,651
  • 5
  • 34
  • 56
  • 1
    If a constructor `return`s an object, the object created by `new` will be discarded. So, `new EventRecordController()` is returning the `function EventRecord` rather than an instance. – Jonathan Lonowski Mar 12 '14 at 12:53
  • Did you want to use revealing module pattern for the `EventRecordController`? Then you're missing the IEFE call – Bergi Mar 12 '14 at 12:59
  • Why is `run` not a function on the `EventRecord` prototype, but a "static" one? – Bergi Mar 12 '14 at 13:00
  • You've got [issues with nested objects](http://stackoverflow.com/questions/4425318/javascript-object-members-that-are-prototyped-as-arrays-become-shared-by-all-cla) because [you're doing the inheritance wrong](http://stackoverflow.com/questions/12592913/what-is-the-reason-to-use-the-new-keyword-here) – Bergi Mar 12 '14 at 13:01
  • 1
    The callback to `util.validate_response_type_and_authenticate` is probably called with the wrong `this` either – Bergi Mar 12 '14 at 13:01
  • `run` was "static" because I was experimenting. It has since been reverted to a prototype. @JonathanLonowski set me on the right course for getting this to work. Thanks @Bergi for pointing out the wrong this in my `validate...` callback. – Jack Slingerland Mar 12 '14 at 13:23

1 Answers1

1

this.error is undefined because run is being called directly on the constructor, which doesn't have an error, rather than one of its instances.

Methods that are attached directly to the constructor aren't inherited. For that, they should be attached to the prototype:

// "static" method available only through the constructor itself
EventRecord.run = function() {
    console.log(this.error);
};

// "class" method inherited by instances of `EventRecord`
EventRecord.prototype.run = function () {
    console.log(this.error);
};

But, you also don't yet have an instance of EventRecord to call .run() on.

When a constructor returns an object, the instance that was created by using new will be discarded. So, calling new EventRecordController() is just returning the function EventRecord.

var controller = new event_record_controller.EventRecordController(req, res);
console.log(typeof controller);     // function
console.log(controller.name);       // "EventRecord"

controller = new controller(req, res);
console.log(typeof controller);     // object

You could revise EventRecordController to return an instance of EventRecord:

// ...

return new EventRecord(req, res);

Though, you might consider consolidating the 2 constructors rather than having one generate the other:

exports.EventRecordController = function(req, res) {
    base_controller.BaseController.apply(this, arguments);
};

util.inherits(exports.EventRecordController, base_controller.BaseController);

exports.EventRecordController.prototype.run = function () {
    console.log(this.error);
};
Jonathan Lonowski
  • 121,453
  • 34
  • 200
  • 199