Is there any way to make “private” variables (those defined in the constructor), available to prototype-defined methods?
TestClass = function(){
var privateField = "hello";
this.nonProtoHello = function(){alert(privateField)};
};
TestClass.prototype.prototypeHello = function(){alert(privateField)};
This works:
t.nonProtoHello()
But this doesn’t:
t.prototypeHello()
I’m used to defining my methods inside the constructor, but am moving away from that for a couple reasons.
You need to change 3 things in your code:
var privateField = "hello"
withthis.privateField = "hello"
.privateField
withthis.privateField
.privateField
withthis.privateField
.The final code would be the following:
There's a simpler way by leveraging the use of
bind
andcall
methods.By setting private variables to an object, you can leverage that object's scope.
Example
This method isn't without drawbacks. Since the scope context is effectively being overridden, you don't have access outside of the
_private
object. However, it isn't impossible though to still give access to the instance object's scope. You can pass in the object's context (this
) as the second argument tobind
orcall
to still have access to it's public values in the prototype function.Accessing public values
No, there's no way to do it. That would essentially be scoping in reverse.
Methods defined inside the constructor have access to private variables because all functions have access to the scope in which they were defined.
Methods defined on a prototype are not defined within the scope of the constructor, and will not have access to the constructor's local variables.
You can still have private variables, but if you want methods defined on the prototype to have access to them, you should define getters and setters on the
this
object, which the prototype methods (along with everything else) will have access to. For example:In current JavaScript, I'm fairly certain that there is one and only one way to have private state, accessible from prototype functions, without adding anything public to
this
. The answer is to use the "weak map" pattern.To sum it up: The
Person
class has a single weak map, where the keys are the instances of Person, and the values are plain objects that are used for private storage.Here is a fully functional example: (play at http://jsfiddle.net/ScottRippey/BLNVr/)
Like I said, this is really the only way to achieve all 3 parts.
There are two caveats, however. First, this costs performance -- every time you access the private data, it's an
O(n)
operation, wheren
is the number of instances. So you won't want to do this if you have a large number of instances. Second, when you're done with an instance, you must calldestroy
; otherwise, the instance and the data will not be garbage collected, and you'll end up with a memory leak.And that's why my original answer, "You shouldn't", is something I'd like to stick to.
see Doug Crockford's page on this. You have to do it indirectly with something that can access the scope of the private variable.
another example:
use case:
Here's something I've come up with while trying to find most simple solution for this problem, perhaps it could be useful to someone. I'm new to javascript, so there might well be some issues with the code.