Javascript 闭包还是创建私有属性的常规构造函数?
我听说闭包的优点之一是能够为对象创建私有属性,如下所示Javascript 闭包还是创建私有属性的常规构造函数?,javascript,Javascript,我听说闭包的优点之一是能够为对象创建私有属性,如下所示 function Func2(){ //A is a closure, kept alive after the Func2 has returned, //After Func2 returns, A is only accessible by getA and setA (it's "private") var A = 100; return { getA: function(){
function Func2(){
//A is a closure, kept alive after the Func2 has returned,
//After Func2 returns, A is only accessible by getA and setA (it's "private")
var A = 100;
return {
getA: function(){
return A;
},
setA: function(newA){
A = newA;
}
}
}
您可以使用getter和setter函数获取和设置使用Func2创建的对象的私有属性A
var obj2 = Func2();
obj2.getA();
obj2.setA(200);
但是,如果我可以使用常规构造函数做同样的事情,那又有什么意义呢
function Func1(){
var A = 100; //A is a private property of any object created with the Func1 constructor
this.getA = function(){
return A;
};
this.setA = function(newA){
A = newA;
};
}
访问私有属性的方法与
var obj1 = new Func1()
obj1.getA();
obj1.setA(200);
正如其他人在评论中指出的那样,在这两种情况下都会创建一个闭包,并且都会起作用 我认为模块模式推荐使用
return
方法的原因是模块模式没有使用Javascript的原型链,因此没有必要使用常规构造函数来创建新的原型(这是不需要的,而且会浪费内存)。在您的示例中,由Func2
创建的对象将只具有默认原型Object.prototype
,而由Func1
创建的对象将具有原型Func1.prototype
,这反过来又具有原型对象.prototype
。另外,Func2
的优点是,它可以使用或不使用new
关键字(不过,如果出于上述原因使用模块模式,最好避免使用new
关键字)。(我曾看到一些程序员抱怨,如果程序员忘记了传统OO Javascript中的new
关键字,可能会导致难以检测的bug;但我个人从未发现这是一个问题)
您可能知道,另一种处理私有变量的方法是简单地在它们前面加上。
,例如:
function Func1() {
this._A = 100;
}
Func1.prototype = {
constructor: Func1,
getA: function(){
return this._A;
},
setA: function(newA){
this._A = newA;
}
};
function Func3(){
var obj = {};
var A = 100;
obj.getA = function(){
return A;
};
obj.setA = function(newA){
A = newA;
};
return obj;
}
就个人而言,我更喜欢这种模式,而不是模块模式——私有变量的主要目标是与其他程序员通信,即“这是一个内部属性;不要直接访问它”——下划线前缀是一种众所周知的约定。私有属性从来没有真正100%地阻止对这些属性的访问,只是劝阻了它(请考虑这样一个事实,即大多数编程语言允许您使用反射来访问私有属性,如果您真的想这样做的话)。此外,只需在前缀中加下划线,就可以轻松地拥有除私有属性外的“受保护”属性(对于子类型/子类很有用)。使用prototype链也更节省内存,因为每个实例没有相同函数的多个副本
但我确实意识到,尽管下划线命名约定很简单,但一些程序员仍然更喜欢使用模块模式,使私有属性从闭包外部无法访问。如果您想这样做,那么我建议使用传统的模块模式,使用return
语句,如第一个示例所示
您可以考虑的另一种模式,如果您喜欢使用模块模式,但仍然想声明公共属性(而不是在<代码>返回/>代码>语句中),将创建一个新对象,并使用该代码而不是<代码> < <代码>,例如:
function Func1() {
this._A = 100;
}
Func1.prototype = {
constructor: Func1,
getA: function(){
return this._A;
},
setA: function(newA){
this._A = newA;
}
};
function Func3(){
var obj = {};
var A = 100;
obj.getA = function(){
return A;
};
obj.setA = function(newA){
A = newA;
};
return obj;
}
(顺便说一句,对于私有方法,与私有数据属性相反,即使使用原型方法,下划线前缀也不是必需的。中的代码示例就是一个例子。)在这两种情况下都有闭包。(不管怎么说,在这两种情况下都是愚蠢的)这不是一个关于“结束与不结束”的问题。这是一个关于“对象文字vs构造函数”的问题。在两个代码段中都创建了闭包。唯一的区别是,在第二种情况下返回的对象(称为Func1)继承自构造函数,而在第一种情况下(Func2)则不是。