所以这是着名的JavaScript模块模式的一个例子:
var Person = (function() {
var _name; // so called 'private variable'
function Person(name) {
_name = name;
}
Person.prototype.kill = function() {
console.log(_name + ' has been shot');
};
return Person;
})();
var paul = new Person('Paul');
paul.kill();
到目前为止这么好吗?这会将'Paul has been shot'
记录到控制台,这就是我们想要的。
但是
_name
真的是私有变量吗?我将私有变量定义为属于对象实例的变量,外部世界无法访问该变量。最后一部分有效,我无法从闭包之外访问_name
。
但如果我这样做:
var paul = new Person('Paul');
var bran = new Person('Bran');
paul.kill();
bran.kill();
然后,这将记录'Bran has been shot'
两次。那里没有保罗。因此_name
实际上与我的Person对象的所有实例共享。这就是我将其定义为“静态变量”,尽管它也无法从外部访问。
那么有没有办法用模块模式创建真正的私有成员变量?一个不是静止的。
同样发生的事情是在构造函数中定义this._name
,但这会杀死私有部分,现在可以从外部访问:
function Person(name) {
this._name = name;
}
var bran = new Person();
console.log(bran._name); // yep, accessible
问题:
因此。私人不是私人的,只是静态的。我们如何使用模块模式创建一个真正的私有成员变量?属于实例的变量,它不是静态的,而是一个无法从外部访问的变量。
答案 0 :(得分:6)
你是对的; _name
更像是一个静态变量。它保存在包含构造函数的闭包中,因此构造函数的每次使用都将使用相同的变量。请记住,这与类无关,而与闭包和函数有关。它可以非常方便,但不是你如何做私人会员。
不出所料,道格拉斯·克罗克福德有page devoted to private members in Javascript。
为了成为私人会员,你必须“更深层次”。不要在构造函数之外使用闭包;使用构造函数作为闭包。构造函数内定义的任何变量或方法显然都不能被外界使用。实际上,对象也无法访问它们,因此它们非常“私密”。
我们想要使用我们的私人会员。 :)那该怎么办?
好吧,在构造函数中,执行以下操作:
var Klass = function () {
var private = 3;
this.privileged = function () { return private; };
};
然后:
var k = Klass();
console.log(k.privileged()); // 3
看看如何使用构造函数作为闭包? this.privileged
依赖于对象,因此private
生活在this.privileged
的封闭内。
不幸的是,Javascript中的私有和特权方法存在一个问题。它们必须每次都从头开始实例化。没有代码共享。这显然是私人会员想要的,但对于方法来说并不理想。使用它们会减慢对象实例化并使用更多内存。如果您遇到效率问题,请记住这一点。
答案 1 :(得分:2)
“真正的私有成员变量”和基于原型的方法并不能很好地协同工作。实现所需的唯一方法是在构造函数中创建所有方法。
var Person = (function() {
function Person(name) {
this.kill = function() {
console.log(name + ' has been shot');
};
}
return Person;
})();
var paul = new Person('Paul');
var bran = new Person('Bran');
paul.kill(); // Paul has been shot
bran.kill(); // Bran has been shot
但由于每个实例都有kill
函数的唯一版本,因此会占用更多内存并且速度较慢。
传统上,下划线前缀用于半私有实例属性,只要暴露的数据不是安全风险。您的javascript代码的大多数消费者都知道不要使用下划线前缀属性。
答案 2 :(得分:2)
问题是你的_name变量在Person范围之外并在所有Person实例之间共享。请执行以下操作:
(function() {
var Person = function(name) {
var _name = name; // so called 'private variable'
this.getName = function()
{
return _name;
}
this.kill = function()
{
console.log(this.getName() + ' has been shot');
}
}
/*Alternative
Person.prototype.kill = function() {
console.log(this.getName() + ' has been shot');
};*/
window.Person = Person;
})();
var paul = new Person('Paul');
var bran = new Person('Bran');
paul.kill();
bran.kill();
答案 3 :(得分:0)
在实例范围中需要为私有的变量必须在此范围内,例如:
function Person(name) {
var _name = name;
this.kill = function() {
console.log( _name + ' has been shot' );
}
}
缺点是必须在也可以访问私有变量的范围中定义kill
。
答案 4 :(得分:0)
为了创建私有var,你应该把它放在构造函数中,所以你的代码应该是这样的:
var Person = (function() {
function Person(name) {
// since name is a param, you don't even have to create a _name var
// and assign name to it
this.getName = function () {
return name;
};
}
Person.prototype.kill = function() {
console.log(this.getName() + ' has been shot');
};
return Person;
})();
var paul = new Person('Paul');
paul.kill();
您还可以在构造函数中声明.kill
:
var Person = (function() {
function Person(name) {
this.kill = function() {
console.log(name + ' has been shot');
};
}
return Person;
})();
var paul = new Person('Paul');
paul.kill();