我听说过闭包的一个优点是能够为对象创建私有属性,如下所示。
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);
答案 0 :(得分:1)
正如其他人在评论中所指出的那样,在这两种情况下都会创建一个闭包,两者都有效。
我认为推荐用于模块模式的return
方法的原因是模块模式没有使用Javascript的原型链,因此不必使用常规模块构造函数,它将创建一个新的原型(不需要它并浪费内存)。在您的示例中,Func2
创建的对象只有Object.prototype
的默认原型,而Func1
创建的对象将具有Func1.prototype
的原型,而Object.prototype
的原型将具有原型Func2
。此外,new
的优势在于它可以使用或不使用new
关键字(尽管如果您使用该模块,最好避免使用new
关键字由于我上面提到的原因,模式)。 (我看到一些程序员抱怨这样一个事实:如果一个程序员在传统的OO Javascript中忘记了_
关键字,它会导致难以发现的错误;我个人从未发现这是一个问题)。
您可能意识到的私有变量的另一种方法是简单地用function Func1() {
this._A = 100;
}
Func1.prototype = {
constructor: Func1,
getA: function(){
return this._A;
},
setA: function(newA){
this._A = newA;
}
};
作为前缀,例如:
return
就个人而言,我更喜欢这个模块模式 - 私有变量的主要目标是与其他程序员的沟通,即"这是一个内部属性;不要直接访问它" - 并且下划线前缀是众所周知的约定。私有财产从来没有真正大约100%阻止访问这些属性,只是不鼓励它(考虑到大多数编程语言允许您使用反射访问私有属性,如果你真的想)。而且,简单地使用下划线加前缀可以让您轻松拥有" protected"属性除了私有属性(对子类型/子类有用)。利用原型链也可以提高内存效率,因为每个实例都没有相同功能的多个副本。
但我确实意识到,尽管下划线命名约定很简单,但是一些程序员仍然更喜欢使用模块模式来真正使私有属性无法从闭包外部访问。如果你想这样做,那么我建议使用传统的模块模式,使用第一个例子中的return
语句。
您可以考虑的另一种模式,如果您更喜欢坚持使用模块模式,但仍希望在进行时声明公共属性(而不是在最后的this
语句中),则可以创建一个模式新对象并使用而不是function Func3(){
var obj = {};
var A = 100;
obj.getA = function(){
return A;
};
obj.setA = function(newA){
A = newA;
};
return obj;
}
,例如:
{{1}}
(顺便说一下,对于私有方法,与私有数据属性相反,即使您正在使用原型方法,下划线前缀也不是必需的。代码示例在this answer中就是一个例子。)