I wish to use https://github.com/mozilla/BrowserQuest/blob/master/server/js/lib/class.js with private inheritable properties and also some getters and setters in there.
Basically I want the getter / setter to modify a private property and subclasses to inherit the setter, getter and the private property of course. This is what I got so far:
var Person = Class.extend({
init: function( name )
{
var name = "~";
this.myName = name;
return {
set myName( value )
{
name = value + " +?";
},
get myName()
{
return name + "^^^^^^^^^";
}
}
}
});
var c = new Person( "cheese" );
console.log(c.myName);
c.myName = "zoom";
console.log(c.myName);
Trace: undefined zoom
Its weird, my editor (Webstorm) sees c.myName as the setter/getter but the compilers consider it an undefined public property :(
Any help would be appreciated. This is Nodejs but I think the issues is javascript.
I'm assuming Node.js or any other environment where the whole EcmaScript 5 is available.
The only way to have true private data in JavaScript these days is to keep a variable in the constructor, which is what you're doing. However, you're confusing the use of return in the init function. While the init function is pretty much the constructor, it is not being called exactly as such, so return does nothing. Even if it did something, what you want is to add a property to this, not return a new object. So basically you'd have to change that return to Object.defineProperty:
init: function (name) {
// notice that the private variable has a different name
// than the parameter
var privateName = '~';
Object.defineProperty(this, 'myName', {
set: function (value) {
privateName = value + " +?";
},
get: function () {
return privateName + "^^^^^^^^^";
}
});
this.myName = name;
}
This still has a limitation in inheritance. If you wanted to inherit from the Person class and modify the getters and setters you'd have to get the property descriptor, modify it and redefine the property. That's painful. And it doesn't support accessing the "super getter/setter". In order to avoid that what we usually do in JavaScript is to forget about having true privates and use privates by convention, starting the private property's name with _. Then you can simply define your getters and setters in the prototype like this:
var Person = Class.extend({
init: function(name) {
// the private name property
this._name = '~';
this.myName = name;
},
set myName(value) {
this._name = value + " +?";
},
get myName() {
return this._name + "^^^^^^^^^";
}
});
This will let you access the super getter/setter when using inheritance.
There is a cutting edge feature that would let you have both true privates and inherit getters and setters: WeakMap. WeakMap is basically an object with creates a relationship between two other objects that doesn't count for garbage collection. That last part is important for memory management and that first part is the one that lets you have true privates. You can try WeakMaps in Beta versions of Firefox and in Node.js with a --harmony_collections flag. Here's how it would work:
function privatize() {
var map = new WeakMap();
return function (obj) {
var data = map.get(obj);
if (!data) {
map.set(obj, data = {});
}
return data;
};
}
var Person = (function () {
var _private = privatize();
return Class.extend({
init: function(name) {
// the private name property
_private(this).name = '~';
this.myName = name;
},
set myName(value) {
_private(this).name = value + " +?";
},
get myName() {
return _private(this).name + "^^^^^^^^^";
}
});
}());