3

I have a prototype function which I use to make two other functions with Object.create(). The private variables, however, are shared. How can I make each instance have its own instance of the variables?

var testCodePrototype = (function(){
  var score = 0;
  this.updateScore= function(amount){
    score += amount;
    return "Score updated to " + score;
  };
  this.getScore = function(){
    return score;
  };
  return {
    updateScore,
    getScore,
  };
}());
      
var test1 = Object.create(testCodePrototype, {
  name: {value: function(type){
   return "I am test1";
  }}
});
var test2 = Object.create(testCodePrototype, {
  name: {value: function(type){
   return "I am second.";
  }}
});

console.log(test1.name());
console.log(test2.name());
console.log(test1.updateScore(5));
console.log(test1.getScore()); // returns 5
console.log(test2.getScore()); // returns 5!!
brentonstrine
  • 21,694
  • 25
  • 74
  • 120
  • You need a constructor function. Or an `init` method. – Bergi Aug 11 '17 at 18:07
  • possible duplicate of [How to create an object with private members using Object.create() instead of new](https://stackoverflow.com/q/11253717/1048572) – Bergi Aug 11 '17 at 18:09

2 Answers2

1

You should create a property score inside each object and use it with this qualifier:

var testCodePrototype = (function(){

    this.updateScore= function(amount){
        this.score += amount;
        return "Score updated to " + this.score;
    };
    this.getScore = function(){
        return this.score;
    };
    return {
        updateScore,
        getScore
    };
}());

var test1 = Object.create(testCodePrototype, {
    name: {value: function(type){
        return "I am test1";
    }},
    score: {writable:true,value:0}
});

var test2 = Object.create(testCodePrototype, {
    name: {value: function(type){
        return "I am second";
    }},
    score: {writable:true,value:0}
});

console.log(test1.name());
console.log(test2.name());
console.log(test1.updateScore(5));
console.log(test1.getScore());  // 5
console.log(test2.getScore());  // 0
brentonstrine
  • 21,694
  • 25
  • 74
  • 120
Thevs
  • 3,189
  • 2
  • 20
  • 32
0

Because JavaScript is a prototypical language, methods and values on a prototype will be shared with all "child" objects, because the objects are live objects (not class templates) and they are linked at runtime. In your case, you are specifying a "private" variable (a variable that is held within a closure) and updating that variable from your child instances. The behavior you're seeing is by design.

In your case, you can't really do what you're looking to do. Prototype functions wouldn't be able to access a "private" variable higher in the inheritance tree. You can do this with "public" variables assigned to the object itself, though this.

One option is to create your new objects and basically rewrite the methods as instance methods. It's understandable that you don't want to do that. However, you could also use a more functional approach, using function currying to achieve your result.