Of course, precedent way is definitively more clear, linear, but if you have a constructor.prototype with a lot of private methods, the overload process will be a wall in front of method execution speed.
Each time you will use a public method, you have to set, and unset, every protected method, and at the same time, as explained in my precedent post, you cannot send the object outside during public method execution, because it will expose every method, protected included.
This new proposal is based on a Function like strategy, applied to instances: apply, and call. Please have a look at this prototype function:
function prototype(constructor, public, protected){
// webreflection - mit style
if(protected){
public.apply = function(callback, arguments){
return (callback.charAt(0) === "_" ? protected : this)[callback].apply(this, arguments);
};
public.call = function(callback){
return this.apply.call(this, callback, Array.prototype.slice.call(arguments, 1));
};
};
public.constructor = constructor;
constructor.prototype = public;
return public;
};
A usage example should be this one:
function MyMath(value){
this.value = value;
};
prototype(
MyMath,
{doStuff:function(){
return this.value * this.value;
}},
{_doStuff:function(){
return this.value + this.value;
}}
);
The first sent object will be the prototype of MyMath constructor, while the second one will contain protected methods.
About performances
As you can see in the simple prototype function, there's no override and no overhead for both public and protected methods. This means that you can use a public method directly and without problems:
var num = new MyMath(3);
num.doStuff(); // direct, fast as regular prototype
About protected methods
These simply "does not exists" :)
var num = new MyMath(3);
num._doStuff(); // error
Protected methods are not directly accessible even from instance itself. This means that these methods are safe and not mutable, if used object is created in a private scope, or runtime as showed before.
How to use protected methods
var num = new MyMath(3);
alert(num.call("_doStuff")); // 6
Apply and call, in this case, are used with instance to call a method that, if contain an underscore as first prefix char, will be one from protected prototype, otherwise will be one of the public prototype. Sounds weird?
// full example
function MyMath(value){
this.value = value;
};
prototype(
MyMath,
{doStuff:function(){
return this.value * this.value;
}},
{_doStuff:function(){
return this.value + this.value;
}}
);
var num = new MyMath(3);
alert([
num.doStuff(), // 9
num.call("doStuff"), // 9
num.call("_doStuff") // 6
].join("\n"));
num._doStuff; // undefined
Why do I call them protected
If everyone can call a method, it does not make sense to call them protected.
But this time, the meaning is not the same of classical inheritance, but it is more close to the word itself: proteced.
The main goal is to have a not common or usual way to call methods, specially for libraries developers.
Every API could be based on public methods, while authors could choose to call a protected method when their need them.
This is basically a transparent layer between the developer and the final user: who will use num.call("doStuff") when you can do this: num.doStuff() ?
I know I am not so good to explain my ideas, so I hope someone will find this useful. Have a nice easter ;)
Very nice.
ReplyDeleteIs it possible to simulate private methods in such way that they are visible from within instance methods, yet completely inaccessible after object instantiation?
Of course it is possible. Just add a closure in the prototype.
ReplyDeletefunction A(value){
this.value = value;
};
A.prototype = new function(){
/* private stuff */
function _doStuff(){
return this.value * this.value;
};
/* public stuff */
this.constructor = A;
this.doStuff = function(){
return _doStuff.apply(this, arguments);
};
};
var a = new A(3);
alert(a.doStuff()); // 9