Reputation: 13
I'm trying to extend one constructor with another, using prototype:
var objA = function(name){
var obj = this;
this.test.name = name;
window.setTimeout(function(){
console.log(obj.test.name)
}, 1)
}
var objB = function(name){
this.name = 'test'
}
objA.prototype.test = new objB();
var a = ['A', 'B', 'C', 'D']
for(var i = 0; i < a.length; i++){
new objA(a[i])
}
This approach works great for one object, but if ( as in this example ) i want to create multiple, it seems that the last entry ( 'D' ) overwrites previous, because in all 4 cases obj.test.name
returns D
. Maybe someone could point out what i'm doing wrong, or maybe other solution for this case. Thanks.
Upvotes: 1
Views: 834
Reputation: 39270
Prototype is like static functions, all instances share one so all instances of objA share a test property that points to the same instance of objB
Normally assigning new values to a property would set that value for the the instance property: Prototypical inheritance - writing up
In this case you assing a value to a property of the prototype and not the prototype so it'll assign a new value for all instances.
var objA = function(name){
var obj = this;
this.test.name = name;
console.log("this.name.is:",this.test.name);
}
var objB = function(name){
this.name = 'test'
}
objA.prototype.test = new objB();
objA.prototype.arr=[];
var a = ['A', 'B', 'C', 'D']
var arr=[];
for(var i = 0; i < a.length; i++){
arr.push(new objA(a[i]))
}
console.log(arr[0].test.name)
arr[0].arr.push("pushed in 0");
console.log(arr[1].arr);
arr[0].arr=["assigned in 0"];
console.log(arr[1].arr);
arr[0].test.name="assigned in 0";
console.log(arr[1].test.name);
Upvotes: 1
Reputation: 44
You should make a "createTest" function rather than a "test" object in the prototyp
Upvotes: -1
Reputation: 119837
JavaScript implements inheritance through chaining objects. objA
has a prototype property test
which is an instance of objB
. This is shared to all instances of objA
objA.prototype.test = new objB();
Now in your constructor for objA
, it modifies objA.prototype.test
which is shared across all instances of objA
. This means that all instances of objA
will have a value of "D" since the last iteration makes the shared property hold "D".
If you want to hold a unique name
property for each instance, you need to attach it to the instance, not the shared parent.
var objA = function (name) {
this.name = name;
}
Now, you seem to notice that there is name
on both instance, and the shared parent. Well, JS reads from the instance first. If it sees a property name
, it takes it's value from there. If not, it reads from the shared parent, where it defaults to 'test'.
It can be seen here, where I made a minor console.log
on them. You can see that the value has 2 name properties, one on the instance, on on the parent, but it reads the instance's value first.
Upvotes: 4
Reputation:
Your problem is setTimeout. You're creating an event handler that runs on the last known information, in this case, when the function is passed 'D'. Without setTimeout, it gives the right values.
You probably want to wrap new objA(a[i]) in a setTimeout instead.
window.setTimeout(function(a){
new objA(a[i]);
}(a), 1);
Because of closures.
Upvotes: 0