0

I know it's possible to mimic private variables in JS:

function ConstructorPattern() {
  var privateVar = 'hi there';

  this.getVar = function() {
    return privateVar;
  };
};

But according to Learning JavaScript Design Patterns when referring to some similar code with class Car and method toString:

The above is a simple version of the constructor pattern but it does suffer from some problems. One is that it makes inheritance difficult and the other is that functions such as toString() are redefined for each of the new objects created using the Car constructor. This isn't very optimal as the function should ideally be shared between all of the instances of the Car type.

So the solution given in my case would be to add the getVar function via the prototype:

ConstructorPattern.prototype.getVar = function() {
  return privateVar;
};

But of course that function has no idea what privateVar is so it doesn't work. I am aware of the module pattern but I specifically want to be able to instantiate multiple instances.

Is there any way to use the constructor pattern "properly" with prototypes while still getting "private" functionality?

EDIT: If there isn't a way to accomplish this, is it really that bad for methods to be redefined for each class instance? I've recently started working on a code base that takes this approach. It seems like the only thing I'm missing out on is inheritance?

EDIT2: Marking as a duplicate based on link from the accepted answer.

anderspitman
  • 9,230
  • 10
  • 40
  • 61
  • not with the constructor pattern (without some hack, which I don't encourage). But, you could acheive a "form" of privacy by using Object.defineProperty(); to make your properties non-enumerable, non-writable, non-configurable. Otherwise module pattern is the way to go. – Sebastien Daniel Sep 16 '14 at 18:17
  • To answer your edit, why use a constructor if you're going to redefine your methods on each instance? – Sebastien Daniel Sep 16 '14 at 18:50
  • They're using the same methods, but a new instance of the method is created for each instantiated object. It's explained in the constructor pattern link above. – anderspitman Sep 16 '14 at 18:58
  • Actually, just to be clear, you're not creating a new instance of the method, you're adding a method in the prototype-chain of your objects. I added an answer with explanations – Sebastien Daniel Sep 16 '14 at 19:03
  • Make your life easier and just don't try to do something that the language doesn't support (yet) ;) – Felix Kling Sep 16 '14 at 19:13
  • @FelixKling that's kinda what I was trying to figure out: whether it's supported or not. – anderspitman Sep 16 '14 at 19:41
  • 1
    Well, no. "Private" properties are simulated by using local variables. Variables are subject to lexical scope. And prototype functions are defined outside the lexical scope of those private variables. – Felix Kling Sep 16 '14 at 19:43
  • @SebastienD. I'm pretty sure when you use the constructor pattern with the methods defined inside the constructor function, that a separate instance of the functions are created for each instantiated object. That's what I was saying. – anderspitman Sep 16 '14 at 19:45
  • @anders yes, you are right. That's not how I had interpreted your comment, my bad! – Sebastien Daniel Sep 16 '14 at 19:52

2 Answers2

3

Is there any way to use the constructor pattern "properly" with prototypes while still getting "private" functionality?

No. This pattern with privileged functions is based on closure scope, and cannot work with shared functions. All privileged methods must be instance-specific.

If there isn't a way to accomplish this, is it really that bad for methods to be redefined for each class instance?

No. Modern JavaScript engines optimize this pattern very well. Sure, there's a little overhead but you won't notice in typical setups.

It seems like the only thing I'm missing out on is inheritance?

Inheritance is still possible, see Define Private field Members and Inheritance in JAVASCRIPT module pattern. Sure, derived subclasses cannot directly access private variables that are declared in a parent constructor, but usually they don't need to anyway.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
0

When you're creating getVar on the object's prototype, it wont be called when you do something like:

objectName.getVar();

Because the prototype's methods come AFTER object methods. An example below will show you what i mean:

function Car() {
  var privy = "hidden";

  this.getPrivy = function() {
    return privy; 
  }
}

Car.prototype = {};
Car.prototype.getPrivy = function() {
  return 'i came from prototype'; 
}

var obj = new Car;
obj.getPrivy();

JS follows a call chain such as: Object method -> prototype method -> prototype prototype method etc.... all the way back to Object.prototype. It stops and returns when a valid method is found. In your case, your instance's method comes BEFORE your prototype's method.

Sebastien Daniel
  • 4,649
  • 3
  • 19
  • 34
  • 2
    This doesn't seem to answer the question at all. – Felix Kling Sep 16 '14 at 19:13
  • It's not an answer to the initial question, its an answer to one of the comments from the main question. ;) – Sebastien Daniel Sep 16 '14 at 19:15
  • The only comment that is not yours (or mine) is *"They're using the same methods, but a new instance of the method is created for each instantiated object. It's explained in the constructor pattern link above."*. And I don't see how this related to what you posted. It seems what you posted is more of a comment than an answer. – Felix Kling Sep 16 '14 at 19:16
  • Yes, but that statement was clearly a misunderstanding, so I chose to shed some light. (you're right it wasn't a clear question). – Sebastien Daniel Sep 16 '14 at 19:16
  • I don't think the OP is misunderstanding anything here, but I can be wrong. – Felix Kling Sep 16 '14 at 19:17