私有和特权方法与原型方法

时间:2011-01-30 01:18:06

标签: javascript oop prototypal-inheritance

在JavaScript中,我可以通过在构造函数中声明它们来创建私有和特权方法。通过这个我必须将它们移出对象的原型。然后我失去了继承和一些性能的可能性,因为每个对象都拥有它自己的那些方法的副本,而不是访问一个原型对象。

所以现在我的问题是什么可能是一个小小的模式:是否使用私有和特权方法。我不喜欢晃来晃去,所以我想避免这种情况。那该怎么办?

您有什么经历?

7 个答案:

答案 0 :(得分:5)

我从未在JavaScript中创建所谓的“私有”函数。只需标记它们以表明它们不属于您的公共API,因此API客户端无法保证该函数将存在,或者在将来的版本中具有相同的实现。

除了API一致性之外,没有理由不让人们只使用你的私人功能。当然,它允许共存脚本与您的私有函数混合,但无论如何,这些脚本可能已经覆盖了您的公共API函数。

这个问题的公认答案对此有很好的评论: Private functions in namespaced javascript

答案 1 :(得分:4)

惯例将是范围内所需要的...以及伪造的私有或受保护成员为您的方法或属性添加下划线的前缀。

我更喜欢伪造的私人/受保护范围......

var MyObject = (function(){
  var interalStaticVar;

  function ctor(arg1, arg2) {
    //create psuedo-protected context
    this._ = {};

    //create a psuedo-private context
    this.__ = {};

    //stash someval
    this.__.someVal = "hands off";
  }

  ctor.prototype.getSomethingPrivate = function() {
    return this.__.someVal;
  }

  ctor.prototype._doSomethingProtected = function(){ ... }

  ctor.prototype.__doSomethingPrivate = function() { ... }

  return ctor;
}());

我会说尝试将OO风格的继承范例应用于JavaScript是在寻找麻烦,可能意味着你做错了什么。我倾向于在浏览器中遵循更多SOLID设计,包含JS的功能事件驱动特性。

答案 2 :(得分:3)

您可以使用

模拟私有或内部方法和属性
obj._foo = private;

obj.prototype._internalMethod;

您需要将自己的私有方法与继承分开。任何可以在不依赖继承的情况下使用的东西都可以正常工作。还有这样的模式:

function construct() { 
    var priv;

    this.someValue = foo;
    this.someMethod = function() { }
}

这里我们忽略原型并直接写入对象。这种依赖闭包隐藏方法和变量的模式适用于mixin。

担心在构造函数中重新声明方法是否效率低是微优化和 evil 。如果您不希望创建至少1000个对象,则差异可以忽略不计。

答案 3 :(得分:3)

我只是猜测你有一些在构造函数中使用的函数,但它们不是公共API的一部分。

在这种情况下,一个选项是将它们作为属性存储在构造函数中。然后在构造函数中调用它们时,您将使用.call()方法设置正在构造的当前对象的上下文。

这样,您可以通过this自动访问公共成员,如果您将其作为参数传递,则可以自动访问私有变量。

var myClass = function() {
    this.someprop = 'prop value';
    var privVar = 'private value';

    myClass.func.call(this, privVar);
};

myClass.func = function(priv){ 
    alert(this.someprop);
    alert(priv); 
};

var inst = new myClass;

因此,这只是将MyClass函数用作构造函数使用的函数的命名空间存储。构造函数从this的上下文中调用它,它使用this.someProperty和传入的privVar执行某些操作。

不确定这是否是你所追求的,但这是一个选择。


正如@Raynos在下面的注释中正确指出的那样,作为简单命名空间存储添加到MyClass构造函数的任何属性都不是私有的,并且可以由任何可以访问构造函数的代码访问

您可以进行一些检查以帮助确保正确调用它,例如添加instanceof检查以确保从MyClass的实例调用它,但此类检查根本不是安全的不提供实际私人会员的保护。

答案 4 :(得分:2)

我认为这一切都取决于你想如何使用你的对象。如果在某个对象中需要私有变量/函数,希望它们可以被该对象的原型方法访问,则必须在构造函数中声明原型方法(顺便提一下example here)。

在我看来,它归结为程序的设计和使用。如果您需要具有真正私有变量或 - 函数的对象,请将其设计为我给出的示例,否则不要。根据我的经验,私有/特权功能并没有真正影响性能。

答案 5 :(得分:0)

创建javascript对象时,我通常会遵循以下模式。

var builders = (function() {
var privateMethod = null;
function builders() {
            this.a_priviledged_method = function() {};
            this.pointerToPrototypeMethod = __bind(this.prototypeMethod, this);
    }
    builders.prototype.prototypeMethod = function(){};
    return builders;
})();
// general method to bind a function call to a context
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };

注意事项:

  1. 'privateMethod'在某种意义上并不是私有的,因为它不在构造函数中,但通过确定范围,可以使它对于将要创建的每个构建器实例都是私有的。
  2. 确保在“创建它们”的上下文中调用原型方法,而不是在它们被调用的上下文中调用。我创建了一个伪特权方法,用于在创建时使用上下文来设置原型方法。对原型方法的后续调用将始终在创建时的上下文中发生。
  3. 由于javascript的方法查找机制决定最后检查原型链,因此'prototypeMethod'之前将''发现''pointerToPrototypeMethod'。
  4. 可以实现类似于'a_priviledged_method'的'pointerToPrototypeMethod',但在这种情况下,每个'构建者'实例都拥有它自己的特权拷贝,导致代码复制。
  5. 在调用私有方法时,应确保通过提供上下文来调用它。例如:在'a_priviledged_method'的主体中,如果想要调用'privateMethod',那么它不应该被称为privateMethod(),而应该被称为privateMethod.apply(this,args)。优点是,如果想要从私有方法调用特权方法而不是在同一个上下文中调用私有方法(对于私有方法的调用)。
  6. 希望这有帮助。

答案 6 :(得分:-1)

(function () {
    function privateFunc () { ... }

    A.prototype.publicFunc1 = function () { ... };
    A.prototype.publicFunc2 = function () { ... };

})();

function A () { ... }

我编辑:如果您还想要私有变量,这无济于事。