Josh K
Josh K

Reputation: 28893

JavaScript Inheritance

If I have an object that I want to "inherit" methods from a "super object" to ensure consitency. They will be intermingling variables. REVISED

ParentObj = function()
{
    var self = this;
    this.interval = null
    this.name = "";
    this.timeout = 1000;

    this.stop = function()
    {
        clearInterval(self.interval);
    };

    this.start = function()
    {
        self.log("Starting up");
        setTimeout(function(){
            self.getData(true);
            self.interval = setInterval(function(){
                self.getData();
            }, self.timeout)
        }, 1000);
    };

    this.log = function(msg)
    {
        require("sys").log(self.name + ": " + msg);
    };

    this.getData = function(override)
    {
        if(override || self.interval)
        {
            /**
            * Allow
            */
            self.log(new Date());
        }
        else
        {
            self.log("Unable to override and no interval");
        }
    }
}

ChildObj = function()
{
    var self = this;
    this.name = "Child";
    this.timeout = 500;
    this.start();
    setTimeout(function(){
        self.stop();
    }, 2000);
}

ChildObj.prototype = new ParentObj();


var c = new ChildObj();

This doesn't seem to work correctly, specifically it not seeing the self.interval and is unable to clear it.

I'm open to other JavaScript inheritance methods, if they exist, but I really need to start encapsulating stuff off into the parent. There are three or four functions that are identical, but being changed at times and this means I have to run through a dozen files to make the change, rather then simply altering the parent.

Working through some of the suggestions I've tried to more clearly define what sort of functionality I'm going for. Ideally all the "children" will have a couple of unique settings (name, interval, config settings) and a getData() method while the parent manages starting, stopping, logging, and anything else.

Upvotes: 1

Views: 445

Answers (3)

naivists
naivists

Reputation: 33551

First thing, I don't think that var this.interval is okay. var keyword is used to define a variable, but in your case you are referencing an object.

Second, if you want to declare "interval" as a method of your cobj, you have to wrap the body of the function in a function.

So, this way it works for me:

var sobj = function()
{
    this.close = function()
    {
        clearInterval(this.interval);
    }
}
 var cobj = function()
{   
   this.initInterval = function(){ this.intervalid = setInterval(function(){ alert("test")}, 5000)};
   this.intervalid = null;
}
cobj.prototype = new sobj();

var inst = new cobj();
inst.initInterval();

After I've defined the constructor functions, I create an actual instance of a "cobj" object and then call "initInterval" to initialize the "setInterval".

UPD: updated the code per @MooGoo's comment.

Upvotes: 0

Dagg Nabbit
Dagg Nabbit

Reputation: 76776

  • 'Clone' an object by making the object the prototype of a throwaway function and calling that function with 'new'.

  • Clone the parent constructor's prototype, and set the result as the prototype of the child class.

...

/**
 * Extend a constructor with a subtype
 * @param {Function} superCtor      Constructor of supertype
 * @param {Function} subCtor        Constructor of subtype
 * @return {Function}               Constructor of subtype
 */
var extend = (function(){

  return function (superCtor, subCtor) {
    var oldProto=subCtor.prototype;
    subCtor.prototype=clone(superCtor.prototype);
    return merge(subCtor.prototype, oldProto).constructor=subCtor; 
  }

  function Clone(){}

  /**
   * Clone an object
   * @param {Object}  obj     Object to clone
   * @return {Object}         Cloned object
   */
  function clone (obj) { Clone.prototype=obj; return new Clone() }

  /**
   * Merge two objects
   * @param {Object} dst      Destination object
   * @param {Object} src      Source object
   * @return {Object}         Destination object
   */
  function merge (dst, src) {
    for (var p in src) if (src.hasOwnProperty(p)) dst[p]=src[p];
    return dst;
  }

}());

Upvotes: 1

C-Mo
C-Mo

Reputation: 1192

Using this inheritance method, you can only mingle variables "upstream." Your child object will be able to see the public properties of its prototype, but the prototype cannot see the properties of its children. It must be self-contained.

(EDIT: I just noticed you're also using "self" without declaring it in sobj.)

sobj = function()
{
    var self = this;
    self.close = function()
    {
        clearInterval(self.interval);
    }

    self.interval = null;
}
cobj = function()
{
    var self = this;
    self.interval = setInterval(function(){ /* Do something */}, 1000);
}
// set cobj.prototype - see explanation below

For how to properly set the prototype (and an in-depth look at how inheritance works in JS), I refer you to Douglas Crockford's book JavaScript: The Good Parts.

He has actually posted how to properly set the prototype on his site. Be sure to use the version that does not touch Object.prototype, as many scripts (jQuery for starters) will break if you change it.

Upvotes: 0

Related Questions