10

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

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

你有什么经验?

4

7 回答 7

5

我从未见过在 JavaScript 中创建所谓的“私有”函数的任何价值。只需以某种方式标记它们以表明它们不是您的公共 API 的一部分,因此 API 客户端不能保证该函数将存在,或者在未来的版本中具有相同的实现。

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

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

于 2011-01-30T01:32:11.913 回答
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 的功能性事件驱动性质。

于 2011-01-30T09:49:03.210 回答
3

您可以使用模拟私有或内部方法和属性

obj._foo = private;

obj.prototype._internalMethod;

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

function construct() { 
    var priv;

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

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

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

于 2011-01-30T01:44:12.427 回答
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.somePropertyprivVar

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


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

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

于 2011-01-30T01:55:40.073 回答
2

我认为这完全取决于你想如何使用你的对象。如果您需要某个对象中的私有变量/函数,并且希望它们可以被该对象的原型方法访问,那么您必须顺便在构造函数中声明原型方法请参见此处的示例)。

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

于 2011-01-30T10:37:22.090 回答
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. 确保在“创建它们”的上下文中调用原型方法,而不是在“调用它们的上下文”中调用原型方法。我创建了一个伪特权方法,该方法在创建时使用上下文的 curry 原型方法。对原型方法的后续调用将始终在创建时的上下文中发生。
  3. 由于 javascript 的方法查找机制规定应最后检查原型链,因此,“pointerToPrototypeMethod”将在“prototypeMethod”之前“发现”。
  4. 可以实现类似于“a_priviledged_method”的“pointerToPrototypeMethod”,但在这种情况下,每个“构建器”实例都将拥有自己的特权方法副本,从而导致代码复制。
  5. 在调用私有方法时,应确保通过提供上下文来调用它。例如:在 'a_priviledged_method' 的主体中,如果想要调用 'privateMethod',则不应将其称为 privateMethod(),而应将其称为 privateMethod.apply(this,args)。优点是,如果一个人想从一个私有方法调用一个特权方法,那么它将在相同的上下文中(对于调用私有方法的内容)。

希望这可以帮助。

于 2013-07-01T14:17:21.913 回答
-1
(function () {
    function privateFunc () { ... }

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

})();

function A () { ... }

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

于 2011-01-30T01:52:33.730 回答