Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript inheritance -- objects declared in constructor are shared between instances?

I am doing Object Oriented programming in JavaScript without Prototype/jQuery (I use jQuery for other stuff). It has been working fine so far, but I ran into an issue with inheritance. Basically, when I declare objects in a constructor, they are shared between instances. Below is some sample code:

    A = function()
    {
        this.y = new Array();
    }

    A.prototype.doStuff = function(n)
    {
        this.y.push(n);
    }

    B = function()
    {
    }

    B.prototype = new A();

    var b1 = new B();
    var b2 = new B();

    b1.doStuff(100);
    b2.doStuff(200);

    console.log("b1:");
    console.log(b1);
    console.log("b2:");
    console.log(b2);

This outputs an array [100, 200] for both b1 and b2. What I want is for b1 and b2 to have their own, separate arrays for y. How do I go about this?

(PS. I assume that Prototype's class system has something built in for this. However I would rather not rewrite a bunch of my code to use that class system)

like image 323
Sam Lee Avatar asked Sep 28 '09 07:09

Sam Lee


2 Answers

The problem is that your A constructor function is only run once for all B instances, and so this.y is a reference to just one array. Any reference to it from B will be resolved via the prototype chain to the single, central A reference, which only has one y. This is a very useful feature, just not for what you're trying to do here.

The answer is to separate construction from initialization; the constructor sets up central resources and the initializer initializes an instance. This is how the issue is handled by most of the "class" implementations I've seen for JavaScript. For that to work, you have to provide a means for each level in the hierarchy to call the previous level's initializer (which is useful for other methods as well) -- e.g., supercalls.

Supercalls are why you're probably better off using something like Prototype for this: They're hard to do well, and it's very easy to fall into the "grandchild" problem -- a solution that seems to work, but ends up only working with a Parent<-Child structure, not a Parent<-Child<-GrandChild structure.

However, if you're going to do your own inheritance mechanism, this post on supercalls from my pathetically-anemic blog may be helpful as I go into some of those issues in depth. It takes a simplified version of Prototype's inheritance mechanism, deconstructs it a bit, and talks about a way to do supercalls that doesn't have some issues I have with Prototype's current supercalls. That may help you with doing them in your own mechanism.

like image 135
T.J. Crowder Avatar answered Oct 08 '22 01:10

T.J. Crowder


B.prototype = new A();

this creates only one instance of A for every B.

You might consider doing sth like

B = function()
{
  this.$super = new A();
}


B.prototype.doStuff = function()
{
  return this.$super(args);
}


C = function ()
{
  this.$super = new B();
}


C.prototype.doStuff = function()
{
  return this.$super(args);
}

C.prototype.whoIsMyGrandParent = function()
{
  return this.$super.$super;
}

Javascript has NO real inheritation

like image 27
jantimon Avatar answered Oct 07 '22 23:10

jantimon