Benas R.
Benas R.

Reputation: 13

javascript - combining two constructors

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

Answers (4)

HMR
HMR

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

simonleung
simonleung

Reputation: 44

You should make a "createTest" function rather than a "test" object in the prototyp

Upvotes: -1

Joseph
Joseph

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

user1508519
user1508519

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

Related Questions