Re: OOP, object literal notation, and the 'new' operator - how to have multiple child objects of a parent object?

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance



"iporter" <isporter@xxxxxxxxx> wrote in message
news:1192714995.047001.28940@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
I wonder if anyone can clear up an OOP issue for me, specifically, how
to have multiple child objects of a parent object. Consider the code
below:

var parentObj={
childCount: 0,
childObj: {
id:false,
init: function() {
alert(this.id);
parentObj.childCount++;
this.id = parentObj.childCount;
alert("Child " + this.id + " Created");
}
}
}

Calling 'parentObj.childObj.init();', the first alert produces
'undefined' and the second 'Child 1 Created'. A second call to
'parentObj.childObj.init();' produces the '1' from above instead of
the 'undefined' I'm expecting - I realise this is because I'm working
with the same object.

However, calling 'var firstChild = parentObj.childObj.init(); var
secondChild = parentObj.childObj.init()' produces the same result (as
does 'var firstChild = parentObj.childObj; firstChild.init();).

I've also tried the 'new' operator. But the code 'var firstChild =
new parentObj.childObj;' produces the error 'parent.childObjis not a
constructor'.

Thus, you can see I'm missing the point - can anyone point me in the
right direction?


Your code above shows a level of confusion that its best just to start
again. I suggest you play around with the following code snippets.

Implementing a parent-detail set of objects option 1:-

function Parent()
{
var m_children = [];

this.add = function(id)
{
var child = new Child(id)
m_children.push(child)
}

this.getCount = function() { return m_children.length; }
this.getItem = function(index) { return m_children[index]; }
}

function Child(id)
{
this.getID = function() {return id;}
}

Usage code might look like:-

var parent = new Parent()
parent.add("Hello")
parent.add("World")
alert(parent.getCount())
alert(parent.getItem(0))
alert(parent.getItem(1))

To implement an OOD in Javascript you first need to choose to what degree
you wish to apply the principle of encapsulation in your development.

The above code has good encapsulation. The down side is that each time an
instance is created the methods need to be redefined if an object has
significant number of methods and/or there are to be as signficant number of
objects instanced this can be a bit expensive.

A different approach to implementing the design would be option 2:-

function Parent()
{
this._children = [];
}
Parent.prototype.add = function(id)
{
var child = new Child(id)
this._children.push(child)
}
Parent.prototype.getCount = function() { return this._children.length; }
Parent.prototype.getItem = function(index) { return this._children[index]; }

function Child(id)
{
this._id = id
}
Child.prototype.getID = function() { return this._id; }

The usage code remains unchanged.

Using prototypes means that methods for various types of objects need only
be defined once. This decreases the cost of instancing new objects. It is
also a good basis for implementing an OOD that includes specialization
(inheritance). The down side is that encapsulation isn't too good. The
'private' object state values are exposed albeit with a convention of being
prefixed with _. Still it may be tempting to some consumer of the object to
access these values directly rather than using the accessor functions.


Another approach is similar to the above where encapsulation is simply
abandoned Option 3:-

function Parent()
{
this.children = [];
}
Parent.prototype.add = function(id)
{
var child = new Child(id)
this._children.push(child)
}

function Child(id)
{
this.id = id
}

Now the usage code looks like:-

var parent = new Parent()
parent.add("Hello")
parent.add("World")
alert(parent.children.length)
alert(parent.children[0])
alert(parent.children[1])

However abandoning encapsulation like the above is so far removed from OOD
that I doubt it would qualify to be call OOD (although specialization may
still be implemented).

My preferred approach is Option 2 but I often match the approach to the
requirement using Option 1 at times and very occasionally I might consider a
little bit of Option 3.


--
Anthony Jones - MVP ASP/ASP.NET


.



Relevant Pages

  • Re: Making a Linked List
    ... Pass $parent by reference, and assign it to the class variable using =&. ... >> languages, I might use a pointer array to other pointer arrays, but in ... > var $parent; ...
    (comp.lang.php)
  • Re: Remove Empty Tags on page
    ... parent, and check for each whether, say, node.firstChild is null and it ... var w = document.createTreeWalker( ... var prev = w.previousNode; ... the parent should be pruned aswell. ...
    (comp.lang.javascript)
  • Re: newb: recurse over elements children and disable all form elements
    ... search a parent elementand search for elements ... you'd have to get all the tags with names that might be form controls, ... var table = document.getElementById; ... ideas - the class filter and testIsChildOf methods seem best to me as ...
    (comp.lang.javascript)
  • Re: WebApp Parent/Child windows
    ... POST the settings dialog and then refresh the parent. ... case, then open the dialog window, keeping the window handle in a var ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: using self.free works better for me, why not???
    ... >> caFree at event close. ... Here your Child Form is diving into the Parent Form's code ... procedure belonging to the Parent would have been cleaner ... TMainForm.SomeCatFormClose(Sender: TSomeCatForm; var Action: ... ...
    (comp.lang.pascal.delphi.misc)