【问题标题】:static method patterns for constructor functions in javascriptjavascript中构造函数的静态方法模式
【发布时间】:2012-02-21 18:32:11
【问题描述】:
function Foo(){...}
Foo.bar = function (){...};

这是向构造函数添加静态方法的唯一模式吗?特别是在Foo()本身的定义中是不是不能创建静态方法bar()?

【问题讨论】:

    标签: javascript methods static design-patterns


    【解决方案1】:
     ( function (fn) {
         fn.bar = function (...) { ... } ;
         ...
     } ) ( Foo.prototype ) ;
    

    换句话说,您创建了一个匿名函数来填充 Foo 的原型。

    【讨论】:

      【解决方案2】:

      当您说“内部”时,听起来您需要一种干净的方式来将所有东西都放在一个地方。您可能会使用支持静态声明的类继承库。或者干脆拿一个并自己扩展它以添加该功能。

      要以简单(但不是那么紧凑)的方式将所有内容放在一起,您可以使用以下方法:

      var Foo = (function () {
          var ctor = function () {
              // the constructor
          };
      
          ctor.staticMethod = function () {
              // something static
          };
      
          return ctor;
      })();
      

      但是!使声明不言自明,它是静态的,到底有多重要?您可以简单地将静态方法声明为原型方法,并通过一些代码 cmets 传达它们是静态(即不作用于实例)方法的事实。这些方法的调用方式不会有任何合同强制执行,但副作用很少。所以我会选择:

      function Foo() {
          // the constructor
          // optionally define instance methods here
      }
      
      Foo.prototype = {
          instanceMethod: function () {
              // some instance method
              // this.bar(); ...
          },
          staticMethod: function () {
              // some static method
              // return 2 + 3;
          }
      };
      

      用法:

      // Using "prototype" explicitly can be your contract for saying "this is static"
      var sum = Foo.prototype.staticMethod();
      
      var inst = new Foo();
      
      var sum2 = inst.staticMethod(); // You have the added benefit of being able to call your static methods on instances
      

      我发现上述方法非常有用,尤其是在您使用工厂设计模式时。您的类可以在其原型中包含一些静态工厂方法,即使您只有一个您不知道其原始类的实例,您也可以调用这些工厂方法。

      【讨论】:

      • 为什么inst 在你的用例中有一个方法sum?你不需要像sum.call(inst)这样的东西吗?
      • 另外,关于“为什么不呢?”问题 - 因为它使您的代码难以阅读并减少代码压缩。
      • sum本质上是“静态的”——它并不真正关心this。在这种情况下绝对不需要使用call
      • 对,但我的意思是,除非我遗漏了什么,否则inst 没有名为sum 的属性——它只有一个名为staticMethod 的属性。你是这个意思吗?
      • @nrabinowitz “难以阅读”是主观的。这完全取决于您定义的约定和合同。请记住,这些经典继承、privates/publics/statics 等都是非 JavaScript 原生的。
      【解决方案3】:

      可以在构造函数中创建静态方法,但只能使用相同的语法:

      function Foo(){
          Foo.bar = function (){...};
      }
      

      但是这只会在调用构造函数后添加静态方法。此外,它会在每次调用构造函数时重新添加它,这似乎很浪费,但我想可能会有用,例如:

      function Foo() {
          var counter = (Foo.bar && Foo.bar() || 0) + 1;
          Foo.bar = function (){
              return counter;
          };
      }
      
      f = new Foo();
      Foo.bar(); // 1
      f2 = new Foo();
      Foo.bar(); // 2
      

      在这种情况下,bar 被更新以返回 Foo 被调用的次数 - 这里可能有一个合理的变体可以以有用的方式跟踪所有实例。

      如果你出于某种原因真的不想引用Foo,你可以聪明地做这样的事情:

      var Foo = (function Private(){
          Private.bar = function (){...};
      });
      

      同样,这只在Foo 至少被调用一次后才有效。此外,虽然这确实演示了另一种语法,但我很难想象您何时可能想要使用它。

      这里还有另一个变体,可能同样没用:

      function Foo() {
          this.constructor.bar = function (){
              console.log("test");
          };
      }
      

      【讨论】:

      • 得到“TypeError: Foo.bar is not a function”。
      • @osoviejo - 是的,请参阅我的更新 - 这仅在您至少调用了一次构造函数后才有效。 没有方法可以在构造函数中做一些在函数运行之前生效的事情。
      • 要求初始实例没有什么“静态的”:(
      • @AtesGoral - 好吧,不是经典意义上的。但它是一个直接附加到构造函数的独立方法,无论如何它都与 Javascript 接近“静态”一样接近。
      • @nrabinowitz True true... 但无论如何,将它附加到构造函数之外更自然,就像 OP 在他们的示例中一样。也许对 OP 问题的回答很简单,“不,这是唯一的方法”。
      猜你喜欢
      • 2012-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多