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)则不是。