I’m trying to have a generic ‘List’ class, which will have:
- Property: Items – which would be an array of ‘what-ever’
- Method: Add() – which would be abstract and implemented by the specific ‘List’ object
- Method: Count() – which returns the number of ‘items’
And then create sub-classes which will inherit from ‘List’:
// Class 'List'
function List(){
this.Items = new Array();
this.Add = function(){ alert('please implement in object') }
}
// Class CDList - which inherits from 'List'
function CDList(){
this.Add = function(Artist){
this.Items.push(Artist)
}
}
CDList.prototype = new List();
CDList.prototype.constructor = CDList;
// Create a new CDList object
var myDiscs = new CDList();
myDiscs.Add('Jackson');
myDiscs.Count() <-- this should be 1
// Create a second CDList object
var myDiscs2 = new CDList();
myDiscs2.Add('Walt');
myDiscs2.Add('Disney');
myDiscs2.Count() <-- this should be 2
…but this seems to create a shared ‘Items’ list for all ‘CDList’ instances. I need to somehow have a new inherited instance of the ‘Items’ list for each ‘CDList’ instance.
How can I do this?
*I’m using in this example the ‘Items’ list as an example. I’d like to be able to have in my sub-classes a new instance for any type of inherited property – not necessarily an Array object.
There is only one Array because you only create one. This array is attached to the prototype of “CDList” and therefore shared between all instances.
To solve this problem: don’t attach it to the prototype, but to the instance. This can only be done at construction time:
Demo: http://jsfiddle.net/9xY2Y/1/
The general concept is: Stuff that each instance must have its own copy of (like the “Items” array in this case) must be created and attached to “this” (= the instance) at construction time, i.e. when doing
new List()ornew CDList(). Everything that can be shared across instances can be attached to the prototype. This essentially means that properties like the “Add” function are created exactly one time and are then used by all instances (what caused the original issue).When linking prototypes, you must not directly link them (usually), e.g.:
Because the prototypes of the three functions “List”, “CDList” and “DVDList” got directly linked to each other, they all point to one prototype object, and that is
List.prototype. So, if you add something toCDList.prototypeyou actually add it toList.prototype– which also is the prototype of “DVDList”.What does the trick is to link the prototype to a new instance of the parent class:
This creates a new object of type “List()” with the special feature that the prototype of the function “List()” is linked to the new object, enabling you to call properties of the prototype directly on the object:
However, remember that we intended to use the body of the function “List()” to create stuff like this array “Items” on a per-instance basis? It is the place where you put any “constructor” code, e.g.
One very clean solution is to use another function to create a prototype-object:
It is now okay to directly link the prototypes, because we will never add anything to
ctor.prototype:If we then do:
the prototype of “CDList()” becomes a new object of type “ctor”, that has no own properties but can be extended, e.g. by a new “Add” function:
However, if you do not add an “Add” property to this new prototype object, the prototype of “ctor()” kicks in – which is the prototype of “List()”. And that’s the desired behavior.
Also, the code in “List()” is now only executed whenever you do
new List()or when you call it directly from another function (in a child class viaList.call(this);).