Say I have this code:
function ParentClass()
{
var anArray = [ ];
this.addToArray = function(what)
{
anArray.push(what);
console.log(anArray);
};
}
FirstSubClass.prototype = new ParentClass();
FirstSubClass.prototype.constructor = FirstSubClass;
function FirstSubClass()
{
this.addToArray('FirstSubClass');
}
SecondSubClass.prototype = new ParentClass();
SecondSubClass.prototype.constructor = SecondSubClass;
function SecondSubClass()
{
this.addToArray('SecondSubClass');
}
When I run new FirstSubClass()
I see a single value array in the console. And when I run new SecondSubClass()
, again, I see a single value array.
However, why is it when I run them again (i.e. new FirstSubClass(); new SecondSubClass();
) I then see the arrays added to rather than new ones being created?
The rationale here is that I'm creating new instances of a class, therefore why are they sharing the same private property?
How can I avoid this so when I do, for e.g., new FirstSubClass()
I then see a single value array no matter how many times I create a new instance of the class?
Say I have this code:
function ParentClass()
{
var anArray = [ ];
this.addToArray = function(what)
{
anArray.push(what);
console.log(anArray);
};
}
FirstSubClass.prototype = new ParentClass();
FirstSubClass.prototype.constructor = FirstSubClass;
function FirstSubClass()
{
this.addToArray('FirstSubClass');
}
SecondSubClass.prototype = new ParentClass();
SecondSubClass.prototype.constructor = SecondSubClass;
function SecondSubClass()
{
this.addToArray('SecondSubClass');
}
When I run new FirstSubClass()
I see a single value array in the console. And when I run new SecondSubClass()
, again, I see a single value array.
However, why is it when I run them again (i.e. new FirstSubClass(); new SecondSubClass();
) I then see the arrays added to rather than new ones being created?
The rationale here is that I'm creating new instances of a class, therefore why are they sharing the same private property?
How can I avoid this so when I do, for e.g., new FirstSubClass()
I then see a single value array no matter how many times I create a new instance of the class?
5 Answers
Reset to default 3Keep in mind that you've only called new ParentClass()
once for each subclass. That means that the private array variable is part of the prototype object for those subclasses. There's only one prototype object, so there's only one array (per subclass).
Each call to new FirstSubClass()
generates a new instance that shares the same prototype object. The call to addToArray()
therefore adds an element to that same array that was created when the prototype object was created.
edit — if you want per-instance arrays, you'd have to do something like this:
function ParentClass() {
this.addToArray = function(value) { this.instanceArray.push(value); };
};
function FirstSubClass() {
this.instanceArray = [];
this.addToArray("First");
}
FirstSubClass.prototype = new ParentClass();
FirstSubClass.prototype.constructor = FirstSubClass;
First, sub-classing in JS is typically a bad idea, because people think that they're getting extension, where every instance has its own copy of properties and methods...
...really, they're getting public static
access to the parent's stuff.
Even better, that public static
stuff has no access to the encapsulated variables, so there's really no manipulation of private data, unless you're using private functions (with a public interface) to pass data to and collect return values from, the public static stuff.
var Parent = function () {
this.static_prop = 0;
this.static_method = function (num) { this.static_prop += 1; return num + this.static_prop; };
};
var Child = function (num) {
this.public_func = function () { num = this.static_method(num); };
};
Child.prototype = new Parent();
var child = new Child(13);
child.public_func();
Just calling this.static_method
wouldn't help, because it would have 0 access to num
, which means that you're wrapping things which you inherited to grant them access to use private data as inputs, which means that you're doing most of the writing you'd be doing anyway, regardless of inheritance, because your expectations of .prototype
were backwards.
Might I suggest Dependency Injection, instead?
Component-based programs?
var Iterator = function () {
var count = 0,
min = 0,
max = 0,
reset = function () { count = min; },
next = function () { count = count >= max ? min : count; return count += 1; },
set_min = function (val) { min = val; },
set_max = function (val) { max = val; },
public_interface = { reset : reset, count : count, set_min : set_min, set_max : set_max };
return public_interface;
},
Thing = function (iter) {
var arr = [],
currentObj = null,
nextObj = function () {
currentObj = arr[iter.next()];
},
add = function (obj) {
arr.push(obj); iter.set_max(arr.length);
},
public_interface = { next : nextObj, add : add };
return public_interface;
};
var thing = Thing(Iterator());
thing.add({});
thing.next();
It's a convoluted example, but now every instance is going to be given exactly what it needs to do its job (because the constructor requires it -- or you can add the dependency later, through a public method, or as a public-property).
The interfaces for each module can now also get as simple and as clean as you'd like, as you don't have to wrap unexpected static-helpers to get private data...
Now you know what's private, you know what you're extending to the public, and you have clean ins and outs wherever you want to put them.
You are only constructing a new instance of ParentClass once per subclass and that is to apply it to your prototype. If you want each instance to have its own copy of the private array and its own copy of the function "addToArray" you will need to invoke the ParentClass constructor function within your other objects constructors:
function ParentClass(){
var anArray = [ ];
this.addToArray = function(what){
anArray.push(what);
console.log(anArray);
};
}
FirstSubClass.prototype = new ParentClass();
FirstSubClass.prototype.constructor = FirstSubClass;
function FirstSubClass(){
//call the parents constructor where "this" points to your FirstSubClass instance
ParentClass.call( this );
this.addToArray('FirstSubClass');
}
SecondSubClass.prototype = new ParentClass();
SecondSubClass.prototype.constructor = SecondSubClass;
function SecondSubClass(){
ParentClass.call( this );
this.addToArray('SecondSubClass');
}
try this:
http://jsfiddle/3z5AX/2/
function ParentClass()
{
var anArray = [ ];
this.addToArray = function(what)
{
anArray.push(what);
document.getElementById("i").value = anArray;
};
}
//FirstSubClass.prototype = new ParentClass();
FirstSubClass.prototype.constructor = FirstSubClass;
function FirstSubClass()
{
this.parent = new ParentClass()
this.parent.addToArray('FirstSubClass');
}
var q = new FirstSubClass();
var r = new FirstSubClass();
All Subclasses share the same parent class, thus the same private anArray
The solution is to use the Mixin pattern.
// I have the habbit of starting a mixin with $
var $AddToArray = function(obj) {
var array = [];
obj.addToArray = function(what) {
array.push(what);
console.log(array);
};
}
var FirstClass = function() {
$AddToArray(this);
}
var SecondClass = function() {
$AddToArray(this);
}