1

EDIT: Fixed my example to demonstrate the behavior.

I wanted the details property of AbstractParent to be what I would call an "instance property" but it's acting more like a "static property". I realize these terms are not appropriate for javascript, so why when I create a new child class does it not get its own unique AbstractParent prototype? Why do they share the same one?

In the code below I expect an empty alert, but instead I get 'new details'

var AbstractParent = Backbone.Model.extend({
  details: [],

  addDetail: function(detail) {
    this.details.push(detail);
  },

  getDetails: function() {
    var rtn = '';
    for(var i=0;i<this.details.length;i++) {
      rtn += this.details[i];
    }
    return rtn;
  }
});

var Child = AbstractParent.extend({});

var ch1 = new Child;
ch1.addDetail("new details");
var ch2 = new Child;

alert(ch2.getDetails()); // => 'new details'

This seems to only work this way when details is an array. If it is a string or an object then it is not shared by ch1 and ch2.

aw crud
  • 8,791
  • 19
  • 71
  • 115

3 Answers3

2

Okay, I figured out the issue. My original question's code was not accurate so I apologize to the other responders (they were correct in the context of the code I presented).

The solution is described here: Javascript object members that are prototyped as arrays become shared by all class instances

Basically, the fact that both Child instances share as their prototype the same AbstractParent function means that changing anything in AbstractParent will be reflected in both of the children's prototypes.

The reason this only manifests itself when using an array is because I initialized the array in the prototype and then just alter it rather than overwriting it in the addDetail function. When I used objects or strings for the property names and then did an assignment, the this in the context at the time of the function call belongs to the Child instance, so doing this.name = 'Billy'; in an AbstractParent function is in fact attaching that to the Child instance instead, and not in the AbstractParent. I was thinking each Child instance would get its own AbstractParent prototype instance and that when I accessed this.name it wouldn't find it on the Child and would go to this.prototype.name instead.

In the code in my question I can fix this by adding an initialize function to AbstractParent that instantiates the details array. But if I were to add an initialize function to the Child and I did not make a call to the parent constructor in it then I would have the same issue as before.

Community
  • 1
  • 1
aw crud
  • 8,791
  • 19
  • 71
  • 115
1

You have assigned a name property (or object) to the base, AbstractParent, and you have defined two Objects which extend from this base. As such, each independently has this name object, though they default to the value assigned in the base.

In your code, though you have assigned ch1.name to 'Billy', you have done nothing to change the value of name for ch2. I contend that your code example is actually wrong. The value displayed by the alert should be 'Default Name'.

Could you load backbone.js in a browser, then go to the debugger console, and enter your above statements in again? If you do, I think you'll find the behavior you expect.

Bill Eisenhauer
  • 6,183
  • 2
  • 30
  • 28
  • You are indeed correct. I distilled my code down to this basic example without testing it, assuming it would behave the same way. I will have to look more closely at my code to see what else I could be doing wrong. In my case I am storing the results of validation in an array in the parent/abstract class, but when I instantiate two copies of the same subclass they are sharing the array of errors. I tested a simplified version of that (as well as the code in my question above) and they both behave differently than I thought. – aw crud May 27 '11 at 11:44
  • I just updated my example with one that I tested to demonstrate the behavior I am experiencing. – aw crud May 27 '11 at 13:25
1

Are you saying when you change ch1.name, it also changes ch2.name? I ran your exact code and did not get that result. ch2.name was still "Default name".

When looking for the name property, my browser took the following routes after setting ch1.name = "Billy"...

ch1

  • inherits.child (your ch1 instance)

    • name: "Billy"

ch2

  • inherits.child (your ch2 instance)
    • __proto__ (your SecondChild prototype)
      • __proto__ (your AbstractParent prototype)
        • name: "Default name"

Open up a debug console, either Firebug in Firefox or Developer Tools / Javascript console in Chrome.

strongriley
  • 1,093
  • 1
  • 15
  • 12
  • You're correct... I must have some other bug in my code because this example I posted does indeed work as you explain. – aw crud May 27 '11 at 11:49