I would make sure to have prototype objects separated from working
objects. I.e., something like (really braindead example domain):
---
function Car(name) {
if (name) { this.name = name; }
}
Car.prototype.getName = function getName() { return this.name; };
Car.prototype.setName = function setName(name) { this.name = name; };
Car.prototype.hasName = function hasName(name) { return "name" in this; };
function Convertible() { this.color = "red"; /*great default!*/ }
Convertible.prototype = clone(Car.prototype);
Convertible.prototype.constructor = Convertible;
Convertible.prototype.getColor =
function getColor() { return this.color; };
Convertible.prototype.setColor =
function setColor(color) { this.color = color; };
---
(where clone is defined as:
function clone(obj) {
function cloner(){};
cloner.prototype=obj;
return new cloner();
}
i.e., it creates a new object with the argument as its prototype)
The above provides a good perspective and insight into Javascript
object construction, and demonstrates a way in which the object model
can be effectively utilized. It's noted as well that it also
illustrates, through the necessity of introduction of the 'clone'
function, one of the fundamental problems, or deficiencies, with the
Javascript language as it currently exists.
Whereas the hierarchical nature of the object model as a mechanism for
provision of prototype inheritance under Javascript is truly quite
wonderful, the facilities provided by the language for manipulation of
the nodes within that structure leave something to be desired. That is,
at least, in my finding.
Why is that? Well, in the development of the object model structure
under program control, everything fundamentally depends on doing
extents from the level above. However, there is a single facility
(ignoring object literals) provided for creating the extensions - the
'new' operator in combination with a so-called 'constructor' function -
that is if not a convoluted mechanism, it is at a minimum an obtuse
mechanism, that fails to present within an object-oriented paradigm.
Not only in the computing sense, but in the literal sense as well.
One contribution to the problem is that the focus is placed almost
entirely on the constructor function. The constructor function, in its
reality, is just a trailing operation to the creation process that
massages and shapes the newly created and delivered object into its
initial (class) form, with that massaging operation occurring
immediately following instantiation of the object into its program
accessible existence. The object's lineage has already been cast by the
time the constructor function is called by having the prototype chain
link imbedded internally in the object by the underlying object
creation process. And where did it get that linkage? -- it was either
pre-assigned within the constructor function object, or attached to the
constructor function through foresightful, anticipatory, program
assignment. Not exactly an intuitive, straightforward mechanism.
So really what's been accomplished by the time you wade through all
this is that an extent has been created from the parent level to the
new object, which in turn has received a final massaging by a function,
which (most unfortunately [1], in my view) is designated 'the
constructor'.
In general, provision of capability to create an extent based on being
in possession of an object reference would be preferable. In the case
of Lasse's example above, that would take the form of:
Convertible.protototype = Car.prototype.extend();
If a trailing massaging, or cultivating, operation is required in the
process of creating the descendant extent, as it most often is, that
would be done as:
oDescendant = o.extend(cFcn, arg1, arg2, ...);
That places the emphasis on the object which provides the underlying
construct of the new object where it really belongs, on the inheritance
it will receive. The 'constructor' function plays the same role as
always, but only as seen to be a finishing operation upon the
instantiation of the newly created object.
With appropriate linkages held in the object, it would be possible then
to extend objects with descendants (which includes
replication/cloning[1-a] - o.parent.extend(..)) in a way that would be,
in my view, much more natural and understandable[2].
While the above doesn't exactly pay great homage to the facilities
fundamentally provided within the language, it is to the credit of
Javascript, that it is possible to add such facility by way of
Object.prototype. That would be to include an Object.prototype.extend
consisting basically of the 'clone' function provided by Lasse above,
and with the addition of an invocation of 'cFcn' by way of Function's
built-in 'call'.
However, in a way that's similarly surprising, adding object capability
through extension of the Object.prototype, introduces a secondary
problem inherent in the language. In doing so, the sole provision for
object iteration by property, the 'for( var iterator in object)'
construct delivers values which then, in many cases, require filtering
through the 'hasOwnProperty' built-in function. This is an unfortunate
consequence that prevents widespread adoption of any enhancements to
the language through inheritance-modification to the top-level object
structure.
This too, once again with respect to the prototyping capability of the
language, along with availability closures, is something for which
compensating functionality can be adequately supplied.
____________
[1] Terminology is important. It appears that 'constructor' as a term
in Javascript has been borrowed from other OO languages without
ensuring that the term really continues to appropriately apply (if it
ever did). The real 'constructor' is the 'new' operation process which
delivers a new object and hooks it into the prototype chain. One
possible alternative for that which is currently termed 'constructor'
would be 'cultivator', to more closely describe the action that
actually occurs. Objects delivered under the application of the
'cultivator' would logically be 'cultivars'. (And I suppose then, a
group of cultivars, which were it not for their subsequent flexible
mutability, might be called a 'cult' ;-)).
[1-a] The designation of 'clone' by Lasse in the creation of a
descendant doesn't really seem to fit. Not in the sense that a clone is
created through delivery of identical genetic material to a physically
independent entity. The term 'clone' seems to be much more applicable
to a sibling replication than to a dependent descendant (ie., the kid,
that it appears, may never leave home ;-)).
[2] as is node construction/manipulation in the DOM.
.../rh