你不希望做的最后一个例子不能工作(它有语法错误),已经被修复了,但我认为你可能想要通常的做法,那就是在构造函数内部创建getter和setter闭包(如下所示)。
不幸的是,如果你想要真正私有的变量,这几乎是你唯一的选择。没有其他方法可以获得真正私有的实例特定变量。但是,请参见下面的“hack”。
这是通常做法的正确版本(我认为你说你不想要,但为了完整起见):
function SomeThing() {
var privateVar;
this.setPrivateVar = function(val) {
privateVar = val;
};
this.getPrivateVar = function() {
return privateVar;
};
}
var t = new Something();
t.setPrivateVar("foo");
console.log(t.getPrivateVar());
和大多数人一样,我第一次在道格拉斯·克罗克福德的网站上读到了这个模式。
这种方法确实有一个缺点:通过SomeThing
构造函数创建的每个实例都有自己的两个函数。它们不能在实例之间共享。因此,如果你的应用程序中将有数百或数千个SomeThing
实例,从内存角度考虑这是需要考虑的问题。如果只有几百个或更少的实例,那么可能并不重要。(这些数字是随意取的,你不应该信任它们,当/如果出现某种问题时,你必须审查代码的内存使用情况;但你明白我的意思。)
解决方法:如果你的实例已经具有某种唯一标识符作为公共数据(或者你愿意添加一个,同样它将是公共的),并且如果你愿意在实例的使用中增加相当多的复杂性,那么你可以拥有一个私有缓存,它仅保存你的代码可以访问的所有实例的数据,并通过对象的唯一标识符键入该缓存。像这样(在这个例子中,我分配了id
值,但如果你已经有了唯一的ID,你也可以使用它):
var SomeThing = (function() {
var cache = {}, idAllocator = 0;
function SomeThing() {
this.id = ++idAllocator;
cache[this.id] = {};
}
SomeThing.prototype.getPrivateVar = function() {
var data = cache[this.id];
return data && data.privateVar;
};
SomeThing.prototype.setPrivateVar = function(value) {
cache[this.id].privateVar = value;
};
SomeThing.prototype.destroy = function() {
delete cache[this.id];
};
return SomeThing;
})();
这是它的工作原理:所有函数都是针对外部作用域函数中的cache本地变量的闭包。我们使用对象的唯一ID进行索引,从而获得一个对象,在该对象上放置私有数据成员。当使用实例的代码完成后,该代码必须调用destroy(这是这种模式的主要缺点),以便我们通过删除id的属性来从cache中删除私有数据对象。
注意事项和成本:
- 你仍然有一个公共数据,即私有数据的关键(如上所述的id)
- 使用SomeThing创建的实例的用户在完成使用后
必须调用这些实例上的destroy。虽然这与JavaScript垃圾处理的方式相悖,但它是上述模式的要求,否则会导致垃圾在cache对象中积累。
- (我不担心这个)最终,如果你使用上述自动id值,如果你的应用程序创建和销毁了很多这些实例,你将耗尽它们。但JavaScript数字确实很高,如果这是一个问题,只需找到一个不同的方法来分配ID,而不是上述简单的始终增加系统。
我还没有在我的工作中使用上述模式,但我期望有用例涉及数千个SomeThing实例,因此不希望每个实例都有函数。
附注:在上面,我将someThing更改为SomeThing。在JavaScript中,标准惯例是普通函数的名称以小写字母开头,构造函数(用于new的函数)的名称以大写字母开头。由于SomeThing用于new,所以我将其大写。这只是约定,但它是一个极其流行的约定,并且当然在语言定义本身中使用(Date是构造函数,setHours是函数)。