VK said:
I see your analysis is up to its usual standard. The OP's question was
about an error produced by trying to call a constructor that required an
object as its argument (because it was interacting which that object
without verifying its existence) without an object as its argument.
That questions has substantially been answered because the various
solutions are: verifying that an object was passed as an argument prior
to treating it as one, or: never calling the constructor without an
object as its argument (and in the case of the posted code not calling
the constructor without an object as its argument by not calling the
constructor to assign a value to another constructor's prototype from
within that second constructor as doing so would not have the desired
result at all if inheritance from the prototype was desired, is
needlessly inefficient and was worthless in this case a no properties of
the resulting object existed that would not be masked by properties
assigned directly to the object).
What you are posting here is irrelevant (though that is normal for you),
and it represents a very dubious notion in the context of implementing
class-style inheritance in javascript as it means that the properties of
the resulting object (rather than just the values of those properties)
depend directly on the arguments passed to the constructor. The result
is a constructor that does not create objects of any single 'type' or
'class' (as conceptually objects of a single class will have the same
properties and methods and just their values will vary between
instances), but instead create an object who's 'class' depends on the
arguments used.
It can be even further adjusted so it would use provided
named arguments and default values for missing arguments.
That gets a bit consuming but it's a regular price to pay:
lesser thinking for a user - more thinking for the engine
One of the consequences of your not comprehending the role of prototypes
in javascript (as was manifest in your bizarre assertion that using
the - new - operator on a constructor and assigning to that
constructor's prototype in the same code was like "trying to speak
French and German at once") is that it leaves you writing the most
phenomenally stupid code:-
<script type="text/javascript">
function MyObject() {
var DEFAULT = {
'prop1' : 1
, 'prop2' : 2
, 'prop3' : 3
};
You realise that that the evaluation of this object literal will result
in the creation of a new, and unique, object with each execution of this
constructor, when each of those objects has the same properties with the
same values? Any strategy that only required one instance of this object
to be created would be superior, and understanding the role of
prototypes in javascript would have allowed you to see a very obvious
strategy for achieving that.
var i;
var p;
for (i=0; i<arguments.length; ++i) {
// only for objects
if (typeof arguments == 'object') {
for (p in arguments) {
// one name : one value
this[p] = arguments[p]; break;
Why the break here? Doesn't that mean that each object that appears in
the argument's list can only contribute a single named property, and so
that a distinct object would be needed to pass each and every named
property to the object? It is bad enough to be creating a new object for
each function call, but not letting a single object contribute multiple
named arguments really is daft.
Though passing multiple objects with multiple properties highlights the
issue of whether properties of a later object should be replacing
properties provided on earlier ones, or vica verca. But even if each
argument object can only contribute the first of its properties
enumerated (enumeration sequences is not guaranteed to be consistent in
javascript, either within the same implementation or across
implementations) there is still a possibility that more than one object
may attempt to contribute a value for the same property of the object
being constructed.
}
}
}
for (p in DEFAULT) {
// default values for missing arguments
if (!(p in this)) {
this[p] = DEFAULT[p];
}
}
}
var obj = new MyObject({'prop2':'foo'},{'prop3':'bar'});
alert(obj.prop1); // 1
alert(obj.prop2); // foo
alert(obj.prop3); // bar
</script>
Apart from allowing constructed object instances to share single
instances of function objects as their methods, prototype inheritance
allows for the defaulting of the values of the properties of constructed
objects. This works because, when a property name is resolved against an
object, if the object has a property of the given name itself it is the
value of that property that is the result, but when the object does not
have the property its prototype chain is examined and the value of the
first property on the prototype chain with the corresponding property is
the result (else it is undefined if no objects on the chain have the
named property).
In the same way as all instances of an object share the instances of
function objects on their prototypes they also share the vales of the
other named properties on their prototypes. This becomes the
standard/natural method of defaulting the vales of object properties in
javascript, and is considerably more efficient than the stupid strategy
you use above as it is achieved passively rather than by actively
enumerating the properties of an object and then testing the results:-
function AnObject() {
var i, p, a, len = arguments.length;
for(i = 0;i < len;++i){
if(typeof (a = arguments) == 'object'){
for (p in a) {
this[p] = a[p];
}
}
}
}
/* With:- */
AnObject.prototype = {
prop1:1,
prop2:2,
prop3:3
};
/* OR:-
AnObject.prototype.prop1 = 1;
AnObject.prototype.prop2 = 2;
AnObject.prototype.prop3 = 3;
- depending on whether the value of the prototype's -
constructor - property is needed to remain a reference
to - AnObject -(which generally does not matter).
*/
var obj = new AnObject({'prop2':'foo'},{'prop3':'bar'});
alert('obj.prop1 = '+obj.prop1);
alert('obj.prop2 = '+obj.prop2);
alert('obj.prop3 = '+obj.prop3);
So that is the same outcome with about half the code and no creating of
a new 'defaulting' object with each execution of the constructor and no
need to loop through the properties of that object in the constructor
either. The arguments either contribute a value that is assigned to a
property of the object itself (masking any default value on the
prototype under the same property name) or it does not and any values
already set on the prototype act as the defaults.
You may assert that javascript is flexible enough to let you get away
with stupid implementations, but knowing how javascript works gives you
the opportunity to do things well, and save much time writing pointless
code along the way.
Richard.