0

I have created collection base class/object to do the repeated task. I have CollectionBase, and I have Persons class that inherit to CollectionBase. but my problem is when i create 2 persons collection like persons1 = new Persons() and persons2 = new Persons() it seems that they have same reference object. Any suggestion on how i can make everytime i will create a new Persons it will create new instance.

Please refer to this on plnkr; http://plnkr.co/edit/8GPkWO4nKRiskxoRWrkg?p=info

(function(){

    function CollectionBase(){
    this.collection = [];
}

Object.defineProperties(CollectionBase.prototype, {
    count: {
        get: function(){
            return this.collection.length;
        },
        enumerable: true
    }
});

CollectionBase.prototype.init = function(){
};

CollectionBase.prototype.get = function(index){
    if (index === undefined){
        return this.collection;
    }
    return this.collection[index];
};

CollectionBase.prototype.remove = function(index){
    try{
        if (index === undefined) throw new Error('index is undefined');
        this.collection.splice(index, 1);
    }
    catch(err){
        console.log(err);       
    }
};

CollectionBase.prototype.update =function(item){
};

CollectionBase.prototype.add = function(item){  
    this.collection.push(item);
};


function Person(firstName, lastName){
    this.firstName = firstName;
    this.lastName = lastName;
}

function Persons(){
    CollectionBase.call(this);
}

Persons.prototype = Object.create(CollectionBase.prototype);

var persons1 = new Persons();
var persons2 = new Persons();

})();

yajra
  • 1,335
  • 2
  • 9
  • 11
  • i already make it to work. just what @jfriend00 said put the property to constructor of base class/object. but i want to make the property to be private, so that if someone will use the base class/object they can will force to use the add, remove, and update method. Any suggestions on this? – yajra Nov 10 '14 at 06:50
  • That's an entirely different question. This post on my blog may help: [*Private properties in ES6 -- and ES3, and ES5*](http://blog.niftysnippets.org/2013/05/private-properties-in-es6-and-es3-and.html). – T.J. Crowder Nov 10 '14 at 06:53
  • ohh i might take a look on that. as you can see for my previous post of the code it uses Object.defineproperties so that i can configure how does the property behave. – yajra Nov 10 '14 at 06:59

1 Answers1

3

Any properties assigned to the prototype are shared among all objects that use that prototype (since the prototype object itself is shared among all instances). This is great for functions on the prototype (e.g. methods), but it is usually bad for data properties because (as you have found), all instances share the same data properties which is not what you usually want.

The usual way to handle this is to assign data properties in your constructor, NOT in the prototype. This creates a new data variable for each new instance of the object.

function CollectionBase(){
   // create new value property for each instance
   this.value = [];
}
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • To be fair, it's fine for primitives. It's object types that cause the trouble, because they never get reassigned. – T.J. Crowder Nov 10 '14 at 06:40
  • Even for arrays it's fine to use the prototype, as when you do a=['a','b'] from the child object, it will not look-up the prototype chain, but directly create a new property in the child object(if not already present), and assign it the value. – Aravind Nov 10 '14 at 06:42
  • @T.J.Crowder - yes, you can put primitives on the prototype, but it's definitely a subtlety to understand what happens when you assign a new value to a primitive that was initially on the prototype. If you just initialize per-instance primitives in the constructor, then you aren't faced with the nuances of that subtlety - life is just simpler. – jfriend00 Nov 10 '14 at 06:47
  • @Aravind - using the prototype with any object (including an array) will not be a per-instance variable if you just modify the object such as `this.a.push("Hello");` That will confused the heck out of someone who doesn't understand the details (such as the OP). Yes, assigning a whole new array to the property will work, but why expose yourself to that complication where modification and assignment work differently. There's rarely a good reason to make your code that subtly complicated. – jfriend00 Nov 10 '14 at 06:48
  • @jfriend00: Yeah, that's certainly what I always do. – T.J. Crowder Nov 10 '14 at 06:52
  • @Aravind & jfriend00 ----> besides the "possible" confusion, What is the real reason that says this is "bad practice" to instantiate on the prototype ie.. array/primitive? Is it because you have broken the prototype/constructor chain from the Super? I am missing the "nuances" you speak of. – james emanon Nov 10 '14 at 07:02
  • @jamesemanon - it's because a data variable on the prototype is shared among all instances (it's like a per-class variable). It is NOT a per-instance variable. But, you usually want a per-instance variable. Putting it on the prototype causes the problem you asked about. Defining it on the newly constructed object in the constructor solves that problem. – jfriend00 Nov 10 '14 at 07:04
  • @james emanon: I took down my answer for reasons of laziness to edit wrong property names, but I do think it's useful to note the point made here: http://stackoverflow.com/questions/572897/how-does-javascript-prototype-work/26830003#26830003 – Aravind Nov 10 '14 at 07:05
  • @jfriend00 -- ok, I believe i was NOT succinct in my question. I am coding an example (personally) and I am adding an array onto the child psuedo-class.. ala childClass1 = new SuperClass(); childClass1.prototype = {}, childClass1.prototype.arr = ['whatever']. Yeah, not onto the Super() = which yes, would be shared by everyone. As I create new child Classes, they do not have access to 'arr' that sits on childClass1. I think I was misunderstanding the flow of this topic :-( – james emanon Nov 10 '14 at 07:10
  • 1
    @jamesemanon - you'd have to show a more complete code example (by editing your question and inserting it there where you can format it too) for me to follow that scenario. In general, ANY array on a prototype is going to be shared by all objects that use that prototype. – jfriend00 Nov 10 '14 at 07:12