繁体   English   中英

使用闭包还是常规构造函数来创建私有属性?

[英]Closure versus regular constructor function for creating private properties?

我听说闭包的优点之一是可以为对象创建私有属性,如下所示。

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的原型,而该原型又具有Object.prototype的原型。 另外, Func2的优点是可以使用new关键字,也可以不使用new关键字(尽管由于上述原因,如果您使用模块模式,最好避免使用new关键字)。 (我已经看到一些程序员抱怨这样一个事实,即如果程序员忘记了传统的OO Javascript中的new关键字,它会导致难以检测的错误;不过我个人从来没有发现这是一个问题)。

您可能已经知道,私有变量的另一种方法是简单地在它们前面加上_ ,例如:

function Func1() { 
    this._A = 100;
}

Func1.prototype = {
    constructor: Func1,

    getA: function(){
        return this._A;
    },

    setA: function(newA){
        this._A = newA;
    }
};

我个人更喜欢这种方式而不是模块模式-私有变量的主要目标是与其他程序员进行通讯,即“这是一个内部属性;不要直接访问它”-下划线前缀是众所周知的约定。 私有属性从来没有真正地100%阻止访问那些属性,只是阻止了它(考虑一下,大多数编程语言都允许您使用反射来访问私有属性这一事实)。 而且,只需在下划线加上前缀即可让您轻松拥有除私有属性(对子类型/子类有用)之外的“受保护”属性。 利用原型链还可以提高内存效率,因为每个实例没有相同功能的多个副本。

但是我确实意识到,尽管下划线命名约定很简单,但是某些程序员仍然喜欢使用模块模式来真正使私有属性无法从闭包外部访问。 如果您想这样做,那么我建议您使用传统的模块模式,如第一个示例所示,使用return语句。

如果您更喜欢使用模块模式,但仍然想声明公共属性(而不是在最后的return语句中),则可以考虑的另一种模式是创建一个新对象,并使用它代替this ,例如:

function Func3(){ 
    var obj = {};
    var A = 100;
    obj.getA = function(){
        return A;
    };
    obj.setA = function(newA){
        A = newA;
    };
    return obj;
}

(顺便说一句,对于私有方法 ,相对于私有数据属性,即使您使用原型方法,下划线前缀也不是必需的。 此答案中的代码示例就是一个示例。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM