1

函数继承的问题是,如果你想创建很多实例,那么它会很慢,因为每次都必须声明函数。

原型继承的问题是没有办法真正拥有私有变量。

是否有可能将这两者混合在一起并获得两全其美的效果?这是我使用原型和单例模式组合的尝试:

var Animal = (function () {
  var secret = "My Secret";

  var _Animal = function (type) {
    this.type = type;
  }
  _Animal.prototype = {
    some_property: 123,
    getSecret: function () {
      return secret;
    }
  };

  return _Animal;
}());

var cat = new Animal("cat");

cat.some_property; // 123
cat.type; // "cat"
cat.getSecret(); // "My Secret"

使用这种模式有什么缺点吗?安全?效率?是否有类似的模式已经存在?

4

2 回答 2

2

你的模式完全没问题。

这里有几件事你要记住。
首先,在最外层闭包中创建的函数和变量的行为类似于其他语言中的私有静态方法/成员(除了它们在语法上的实际调用方式)。

如果您使用原型范例,那么创建私有静态方法/成员当然是不可能的。
您可以通过将它们附加到内部构造函数来进一步创建公共静态成员/方法,然后再将其返回到外部范围:

var Class = (function () {
    var private_static = function () {},
        public_static  = function () {},

        Class = function () {
            var private_method = function () { private_static(); };
            this.method = function () { private_method(); }; 
         };

    Class.static = public_static;
    return Class;
}());

Class.static(); // calls `public_static`
var instance = new Class();
instance.method();
// calls instance's `private_method()`, which in turn calls the shared `private_static();`

请记住,如果您打算以这种方式使用“静态”函数,它们绝对无法访问实例的内部状态,因此,如果您确实使用它们,则需要向它们传递任何东西他们需要,您必须收集返回语句(或从内部修改对象属性/数组元素)。

此外,从任何实例内部,给定上面的代码,public_static并且Class.static();都是调用公共函数的完全有效的方法,因为它实际上不是静态的,而只是闭包中的一个函数,它也恰好被添加为一个属性另一个对象,它也在实例的范围链内。

额外的好处:
即使恶意代码 DID 开始攻击您的公共静态Class.static方法( - 安全至于让人们远离私有的东西...... 如果另一个模块依赖于一个实例,并且该实例的公共方法已被篡改,而另一个模块只是信任它所提供的一切......好吧,该模块的创建者感到羞耻——但至少你的东西是安全的。Class.staticpublic_static

万岁用于复制其他语言的功能,仅使用闭包。

于 2013-03-26T00:56:35.847 回答
1

是否有可能将功能继承和原型继承混合在一起并获得两全其美?

是的。你应该这样做。您可以使用从放置所有非特权方法的某个 proto 对象继承,而不是初始化that为。但是,从这样的“类”继承并不简单,您很快就会得到看起来更像伪经典方法的代码——即使使用工厂。{}Object.create

我尝试结合使用原型和单例模式。是否有类似的模式已经存在?

好的,但这与上面的不同吗?实际上,这被称为“Revealing Prototype Pattern”,是模块模式和原型模式的结合。

使用这种模式有什么缺点吗?

不,还好。仅对于您的示例,这有点不必要,并且由于您secret是一种静态变量,因此对我从实例方法访问它没有多大意义。更短:

function Animal(type) {
    this.type = type;
}
Animal.prototype.some_property = 123;
Animal.getSecret = function() {
    return "My Secret";
};
于 2013-03-26T01:13:24.800 回答