【问题标题】:Question about functional OOP style in JavaScript关于 JavaScript 中函数式 OOP 样式的问题
【发布时间】:2010-01-04 12:31:02
【问题描述】:

我更喜欢对我的代码使用函数式 OOP 样式(类似于模块模式),因为它可以帮助我避免“new”关键字以及回调中“this”关键字范围的所有问题。

但我遇到了一些小问题。我想使用下面的代码来创建一个类。

namespace.myClass = function(){
  var self = {},
      somePrivateVar1;

  // initialization code that would call
  // private or public methods
  privateMethod();
  self.publicMethod(); // sorry, error here

  function privateMethod(){}

  self.publicMethod = function(){};

  return self;
}

问题是我不能从我的初始化代码中调用公共方法,因为这些函数还没有定义。显而易见的解决方案是创建一个 init 方法,并在“return self”行之前调用它。但也许您知道更优雅的解决方案?

另外,您通常如何使用这种模式处理继承?我使用以下代码,但我想听听您的想法和建议。

namespace.myClass2 = function(){
  var self = namespace.parentClass(),
      somePrivateVar1;            

  var superMethod = self.someMethod;
  self.someMethod = function(){
    // example shows how to overwrite parent methods
    superMethod();
  };

  return self;
}

编辑。 对于那些询问选择这种 OOP 风格的原因的人,您可以查看以下问题:

【问题讨论】:

  • 不使用语言提供的技术通常是一个的想法。这意味着您不应该规避new,这正是它在 Javascript 中完成的方式,它可能是在这种特定语言中的最佳方式。
  • 为什么不能在顶部定义方法,然后再尝试调用它们?
  • 请记住,除非您引入“特权”getter 和 setter 方法,否则您将无法从后代类访问父类中的“私有”变量。 myClass2 中的“somePrivateVar1”将是 myClass1 中同名 var 的单独变量,其中一个变量的任何更改都不会反映在另一个变量中。这可能会给您带来很多困惑。
  • 关于被覆盖的方法,你实际上想要实现什么?到目前为止,您看起来还不错,尽管我可能会建议为“超级”方法添加私有名称空间(例如: var superMethods = {}; superMethods.someMethod = self.someMethod; self.someMethod = function(){ superMethods .someMethod(); //... }) 或者您是否正在寻找一种方法来自动在新覆盖的方法中包含对 superMethod 的调用?
  • 我试图了解这种方法的实用性。那里没有更高阶的程序,实际上有很多突变。更不用说由于对象突变导致的主要问题是执行顺序。

标签: javascript oop coding-style


【解决方案1】:

您可以使用Zet.js 库,它将帮助您以您想要的方式声明类。

【讨论】:

    【解决方案2】:

    我想到了几个问题,例如为什么要避免使用new 运算符,以及为什么要在定义函数之前调用它们。但是,撇开这些不谈,像下面这样的东西怎么样?

    namespace.myClass = function(){
      var somePrivateVar1;
      var self = {};
    
      // initialization code that would call
      // private or public methods
      privateMethod();
      publicMethod();
    
      function privateMethod(){}
      function publicMethod(){}
    
      self.publicMethod = publicMethod;
      return self;
    }
    

    【讨论】:

    • 谢谢,这种方法的一个问题是您没有对类中当前对象的引用。但在我的示例中,可以使用 self 变量将对象本身传递给另一个函数,例如。 someFunctionThatRegistersAnObject(self);
    • 我尝试为您的答案投票,但 stackoverflow 显示错误“投票太旧无法更改,除非此答案已编辑”。这是一个错误吗?
    • @valums:答案已更改以解决您的评论。不确定 SO 错误,但现在我已经编辑了答案,您应该可以更改您的投票了。
    • 谢谢,这也行,但我认为在底部重新声明方法看起来不太干净。
    • 它并没有像这样重新声明一个方法:只有两个单独的语句用于声明一个函数,然后将该函数分配为self 的方法。我同意这种风格不是很讨人喜欢,但它符合您的一系列要求。
    【解决方案3】:

    我同意到目前为止提供的几乎所有评论或答案,但为了让 Tim 的答案更进一步——他质疑为什么你想在定义方法之前调用它,但无论如何提供了一个解决方案,而我会建议你不应该在定义之前调用(我不知道在定义方法之前调用方法或至少声明它被认为是好的做法的任何语言),那么如何:

    namespace.myClass = function(){  
      //declare private vars (and self) first
      var self = {},  
          somePrivateVar1;  
    
      //then declare private methods
      function privateMethod(){}  
    
      //then public/privileged methods
      self.publicMethod = function(){};  
    
      // THEN (and only then) add your 
      // initialization code that would call  
      // private or public methods  
      privateMethod();  
      self.publicMethod(); // no error any more
    
      //then return the new object
      return self;  
    } 
    

    这对你不起作用有什么特别的原因吗?

    【讨论】:

    • 谢谢,这样可以的,但我宁愿把构造函数放在最上面,因为它很常见,我不想破坏其他程序员的习惯。
    【解决方案4】:

    这是我在问题中提到的解决方案。欢迎您的 cmets。

    namespace.myClass = function(){
      var self = {},
          somePrivateVar1;
    
      function init(){
        privateMethod();
        self.publicMethod();
      }
    
      function privateMethod(){}
      self.publicMethod = function(){};
    
      init();
      return self;
    }
    

    【讨论】:

    • 这行得通,如果你承诺在顶部有初始化代码,在声明你的任何方法之前,这将是唯一的方法,据我所知。我唯一的评论是,这不是您所要求的“优雅”,但是我的 个人 意见是,您希望该方法如何“看起来”的标准无论如何都不优雅 -所以在这个标准内,你所拥有的可能是最好的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多