Reputation: 3491
Well I have this constructor with one secret and one method:
function Keeper(get) {
var secretPower = 'wisdom';
this.get = get ? get : function () {
return 'Its secret power is: ' + secretPower;
}
// now this is privileged method only in case that there are no arguments?
}
Now I will make two instances, one has privileged method...
var yourKeeper = new Keeper();
yourKeeper.get(); // "Its secret power is: wisdom"
... but the another one is different. It can touch context around it, but not privates of the constructor ...
var myKeeper = new Keeper(function() {
return 'Its secret power is: ' + secretPower;
});
myKeeper.get(); // ReferenceError: secretPower is not defined
... also this doesn't work as I want:
myKeeper.get = function() {
return 'Its secret power is: ' + secretPower;
}
myKeeper.get(); // ReferenceError: secretPower is not defined
Of course it won't work, because secretPower
is global variable in these cases, so:
var secretPower = 'none';
myKeeper.get(); // "Its secret power is: none"
So is it possible to define priviledge method outside of the constructor? How?
Can it be done with eval? (I know... it is evil... Im just interested)
Upvotes: 2
Views: 239
Reputation: 4984
I would never actually do it this way but here is a solution with eval
:
function test(){
var private = 'hello';
this.say = function(){
}
this.setSay = function(func){
eval('this.say = ' + func.toString());
}
}
var x = new test();
x.setSay(function(){
console.log(private + ' world');
});
x.say();
example http://jsfiddle.net/claustrofob/AwMd3/
And here is an example related to your Keeper
object:
function Keeper(get) {
var secretPower = 'wisdom';
var getFunc = function () {
return 'Its secret power is: ' + secretPower;
};
var evalFunc = function(variable, val){
eval(variable + ' = ' + val.toString());
};
this.__defineSetter__("get", function(val){
evalFunc('getFunc', val);
});
this.__defineGetter__("get", function(val){
return getFunc;
});
if (get !== undefined){
evalFunc('getFunc', get);
}
}
here we define setter and getter for your get
method so you can init your objects this way:
var x = new Keeper(function () {
return 'Its secret power is: ' + secretPower;
});
and this way:
var x = new Keeper();
x.get = function () {
return 'Its secret power is: ' + secretPower;
};
live example http://jsfiddle.net/claustrofob/yu6VJ/
Upvotes: 1
Reputation: 74234
Yes it's possible to define privileged methods outside of the constructor. Here is how to do it:
var Keeper = (function (key) {
function Keeper(get) {
var private = {
secretPower: "wisdom"
};
this.getPrivate = function (k) {
if (k === key) return private;
};
this.get = get || defaultGet;
}
function defaultGet() {
var private = this.getPrivate(key);
return "The secret power is: " + private.secretPower;
}
return Keeper;
}({}));
Here is how it works:
key
. This object is private to the namespace we just created. Hence only privileged functions and the constructor can access it.private
which holds the private state of each instance.getPrivate
which takes an argument k
and only returns the private object if k
is the key
we created in step 2. Hence only privileged functions can access the private object.getPrivate(key)
to get the private state object.Note: This method is only useful if you have more than one privileged function which needs to access the private state of the object. In addition the call the getPrivate
introduces a (very) small performance overhead to privileged functions.
BTW if you want to write clean object-oriented code in JavaScript then take a look at the augment
library. The above code will looks like this using augment
:
var Keeper = Object.augment(function (key) {
this.constructor = function (get) {
var private = {
secretPower: "wisdom"
};
this.getPrivate = function (k) {
if (k === key) return private;
};
this.get = get || defaultGet;
};
function defaultGet() {
var private = this.getPrivate(key);
return "The secret power is: " + private.secretPower;
}
}, {});
Upvotes: 2
Reputation: 27020
The very idea behind the scoping in javascript is that this shouldn't be possible, what I would advice is adding a function getPrivate
within the scope of the constructor and use that to access 'private' variables.
function Keeper(get) {
var semiPrivates = {
secretPower:'Wisdom'
}
this.getPrivate = function (variable){
return semiPrivates[variable];
}
this.get = get ? get : function () {
return 'Its secret power is: ' + semiPrivates["secretPower"];
}
}
Upvotes: 2