我希望https://github.com/mozilla/BrowserQuest/blob/master/server/js/lib/class.js使用私有的可继承属性,还有一些getter和setter。
基本上我希望getter / setter修改私有属性和子类来继承setter,getter和private属性。 这是我到目前为止所得到的:
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);
跟踪: 未定义 变焦
很奇怪,我的编辑器(Webstorm)将c.myName视为setter / getter,但编译器认为它是一个未定义的公共属性:(
任何帮助将不胜感激。这是Nodejs,但我认为问题是javascript。
答案 0 :(得分:4)
我假设Node.js或整个EcmaScript 5可用的任何其他环境。
这些天在JavaScript中拥有真正私有数据的唯一方法是在构造函数中保留一个变量,这就是你正在做的事情。但是,您在return
函数中使用init
时会感到困惑。虽然init
函数几乎就是构造函数,但它并没有被完全调用,所以return
什么都不做。即使它做了某些事情,你想要的是向this
添加一个属性,而不是返回一个新对象。所以基本上你必须将return
更改为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;
}
这仍然有继承限制。如果您想继承Person类并修改getter和setter,则必须获取属性描述符,修改它并重新定义属性。那很痛苦。并且它不支持访问“超级getter / setter”。为了避免我们在JavaScript中通常做的就是忘记拥有真正的私有并按惯例使用私有,使用_
启动私有属性的名称。然后你可以简单地在原型中定义你的getter和setter:
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 + "^^^^^^^^^";
}
});
这将允许您在使用继承时访问超级getter / setter。
有一个先进的功能可以让你拥有真正的私有和继承getter和setter:WeakMap。 WeakMap基本上是一个对象,它在另外两个不计入垃圾收集的对象之间创建关系。最后一部分对于内存管理很重要,第一部分是让你拥有真正私有的部分。您可以尝试使用Beta版本的Firefox和带有--harmony_collections
标志的Node.js中的WeakMaps。以下是它的工作原理:
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 + "^^^^^^^^^";
}
});
}());