Search code examples
javascriptecmascript-5

How to declare data structures on base objects, so they remain independent in each extended object?


Example:

var Person = {
   name : '',
   collection  : new Array(),
   addToCollection : function(x)
   {
     this.collection.push(x);
   },
   printCollection: function() {
       console.log(this.collection);
   }
};


var skywalker = Object.create(Person);
skywalker.name = 'Anakin Skywalker';
skywalker.addToCollection(1);
skywalker.printCollection();   // prinnts [1]


var skywalker2 = Object.create(Person);
skywalker2.name = 'Anakin Skywalker 2';
skywalker.addToCollection(2);
skywalker2.printCollection();   // prints [1, 2]

I would like to achieve situation where skywalker2.printCollection(); prints [2]. I want the base object Person to be concerned with collection, and expose operations such as addToCollection(x).


Solution

  • You have to do like this;

    var Person = {
       name : '',
       addToCollection : function(x)
       {
         this.collection.push(x);
       },
       printCollection: function() {
           console.log(this.collection);
       }
    };
    var sw1 = Object.create(Person),
        sw2 = Object.create(Person);
    
    sw1.collection = new Array();
    sw2.collection = new Array();
    sw1.addToCollection(1);
    sw2.addToCollection(2);
    
    sw1.printCollection(); // <- 1
    sw2.printCollection(); // <- 2

    Well as per the comment of the OP a little info on Object creation in JS. Object.create() will let you define the prototype of an object and anything in the prototype are shared among the instantiated objects. So in this case the collection array is shared. If you don't want the collection to be shared you just have to create it within the instantiated object as i have shown in the previous snippet. However as i understand you don't want that. OK then there is one more way to achieve this. We can have the collection array under a function as a private property and access it by a closure through our prototype methods. Then we will achieve what we wanted. Just like this;

    function collectionInClosure(){
      var collection = [],
       getCollection = function(){return collection},
       setCollection = function(v) {collection.push(v)};
      return {
               printCollection: function() {console.log(getCollection())},
               addToCollection: setCollection
             };
    }
    
    var sw1 = Object.create(collectionInClosure());
        sw2 = Object.create(collectionInClosure());
    
    sw1.addToCollection(1);
    sw2.addToCollection(2);
    
    sw1.printCollection(); // <- 1
    sw2.printCollection(); // <- 2