To make a JavaScript class with a public method I'd do something like:
function Restaurant() {}
Restaurant.prototype.buy_food = function(){
// something here
}
Restaurant.prototype.use_restroom = function(){
// something here
}
That way users of my class can:
var restaurant = new Restaurant();
restaurant.buy_food();
restaurant.use_restroom();
How do I create a private method that can be called by the buy_food
and use_restroom
methods but not externally by users of the class?
In other words, I want my method implementation to be able to do:
Restaurant.prototype.use_restroom = function() {
this.private_stuff();
}
But this shouldn't work:
var r = new Restaurant();
r.private_stuff();
How do I define private_stuff
as a private method so both of these hold true?
I've read Doug Crockford's writeup a few times but it doesn't seem like "private" methods can be called by public methods and "privileged" methods can be called externally.
See this answer for a a clean & simple 'class' solution with a private and public interface and support for composition
Take any of the solutions that follow Crockford's private or priviledged pattern. For example:
In any case where the attacker has no "execute" right on the JS context he has no way of accessing any "public" or "private" fields or methods. In case the attacker does have that access he can execute this one-liner:
Note that the above code is generic to all constructor-type-privacy. It will fail with some of the solutions here but it should be clear that pretty much all of the closure based solutions can be broken like this with different
replace()
parameters.After this is executed any object created with
new Foo()
is going to have aneval
method which can be called to return or change values or methods defined in the constructor's closure, e.g.:The only problem I can see with this that it won't work for cases where there is only one instance and it's created on load. But then there is no reason to actually define a prototype and in that case the attacker can simply recreate the object instead of the constructor as long as he has a way of passing the same parameters (e.g. they are constant or calculated from available values).
In my opinion, this pretty much makes Crockford's solution useless. Since the "privacy" is easily broken the downsides of his solution (reduced readability & maintainability, decreased performance, increased memory) makes the "no privacy" prototype based method the better choice.
I do usually use leading underscores to mark
__private
and_protected
methods and fields (Perl style), but the idea of having privacy in JavaScript just shows how it's a misunderstood language.Therefore I disagree with Crockford except for his first sentence.
So how do you get real privacy in JS? Put everything that is required to be private on the server side and use JS to do AJAX calls.
The module pattern is right in most cases. But if you have thousands of instances, classes save memory. If saving memory is a concern and your objects contain a small amount of private data, but have a lot of public functions, then you'll want all public functions to live in the .prototype to save memory.
This is what I came up with:
The object
priv
contains private properties. It is accessible through the public functiongetPriv()
, but this function returnsfalse
unless you pass it thesecret
, and this is only known inside the main closure.You can simulate private methods like this:
More information on this technique here: http://webreflection.blogspot.com/2008/04/natural-javascript-private-methods.html
Using self invoking function and call
JavaScript uses prototypes and does't have classes (or methods for that matter) like Object Oriented languages. A JavaScript developer need to think in JavaScript.
Wikipedia quote:
Solution using a self invoking function and the call function to call the private "method" :
The call function allows us to call the private function with the appropriate context (
this
).Simpler with Node.js
If you are using node.js, you don't need the IIFE because you can take advantage of the module loading system:
Load the file:
(experimental) ES7 with the Bind Operator
The bind operator
::
is an ECMAScript proposal and is implemented in Babel (stage 0).Load the file:
What about this?
Private variable lookup is impossible outside of the scope of the immediate function. There is no duplication of functions, saving memory.
The downside is that the lookup of private variables is clunky
privateVars[this.id].cooked
is ridiculous to type. There is also an extra "id" variable.