Reputation: 9359
Some methods of one of my classes right now are public, but can access private variables (they are privileged). This is because they are created in the class constructor, so their closure has access to the object closure.
What I would like to avoid, though, is the memory and performance overhead of creating new privileged methods every time. So I want to share them.
Is there any way to put privileged methods into a prototype?
Example was requested:
function Person(age) { // age is private
this.grow = function() { // grow is now public, but can access private "age"
age += 1;
}
}
dan = new Person(10);
dan.grow();
dan.age; // undefined
This works, I have a public method "grow" that can access the private variable "age", but grow has to be recreated for each object.
The more performant way is:
function Person(age) { // age is private
this.age = age; // but this.age is public
}
Person.prototype.grow = function() {
this.age += 1;
}
dan = new Person(10);
dan.grow();
dan.age; // 11
This shares the "grow" method, but now age is public.
Upvotes: 2
Views: 181
Reputation: 74234
Yes, it is indeed possible. However it requires a little bit of trickery:
var createTree = require("functional-red-black-tree");
var Person = (function () {
var tree = createTree(), id = 0;
return function (age) {
tree.insert(id, {
age: age
});
this.id = id++;
this.grow = grow;
this.destroy = destroy;
};
function grow() {
tree.get(this.id).age++;
}
function destroy() {
tree.remove(this.id);
}
}());
We use functional red black trees to efficiently insert, remove and get the private properties of an object in O(log n)
time. Hence for example say you create 2251799813685248 instances of Person
at a time. It will still only require 51 operations to insert, remove and get objects from the tree.
You can use it as follows:
var dan = new Person(10);
dan.grow();
dan.age; // undefined
dan.destroy(); // frees shared memory
However I wouldn't recommend this approach because:
destroy
then you will waste a lot of memory.secret
object are not reflected on the private variables.Instead I would recommend that you just use public properties for everything. There's really no good reason to use private properties at all. What are you scared of?
Edit: If alll you want is to prevent your private properties from being printed out via console.log
then you can make them non-enumerable:
function Person(age) {
Object.defineProperty(this, "age", {
enumerable: false,
writable: true,
value: age
});
}
Person.prototype.grow = function () {
this.age++;
};
Now the age
property (although public) will not appear in for in
loops or via console.log
. In short you get the best of both worlds.
As I said in the comments, there's absolutely no need to use the shared privileged method hack. Simply make all your variables public and non-enumerable.
In addition prefix them with an underscore to indicate that they should not be tampered with. All good JavaScript programmers use this convention.
Upvotes: 1
Reputation: 23492
You could do something like this (without ES6), though I don't consider it a good solution.
var Person = (function () {
var id = 0,
data = {},
key = Math.random();
function Person(age) {
var thisId = id;
data[id] = age;
id += 1;
this.getId = function(check) {
if (check !== key) {
return undefined;
}
return thisId;
};
}
Person.prototype.grow = function () {
var thisId = this.getId(key);
data[thisId] += 1;
console.log(data[thisId]);
return this;
};
Person.prototype.destroy = function () {
var thisId = this.getId(key);
data[thisId] = null;
delete data[thisId];
};
return Person;
}());
var dan = new Person(10);
dan.grow();
console.log(dan.age); // undefined
console.log(dan.getId()); // undefined
on jsFiddle
Added by @DanRedux:
function Person(age) {
this.private = {age:age}; }
Person.prototype.grow = function() {
this.private.age += 1; }
dan = new Person(10);
dan.grow();
dan.age; // undefined
dan.private.age; // 11
Upvotes: 1
Reputation: 665070
Well, as you have said, privileged methods are created by placing them in the constructor scope. By that definition, they cannot be shared amongst instances; otherwise they wouldn't be able to access the instance-specific scope.
Upvotes: 0