【问题标题】:Should I use polymorphism in javascript?我应该在javascript中使用多态性吗?
【发布时间】:2012-04-08 16:52:37
【问题描述】:

我是一名程序员,曾使用多种语言进行编程,包括函数式和面向 OO 的。我也编写了一些 Javascript,但从未在其中使用(或不得不使用)多态性。

现在,作为一个爱好项目,我想将一些用 Java 和 C# 编写的、大量使用多态性的应用程序移植到 Javascript 中。

但乍一看,我读了很多“有可能,但是……”

那么有没有替代品呢?

我想用伪语言用 JS 写的一个例子:

abstract class Shape{ { printSurface() } ;  }

class Rect : Shape() {  printSurface() { print (sideA*sideB}}

class Circle : Shape() {  printSurface() { print { pi*r*r }}

TheApp { myshapes.iterate(shape s) {s.printSurface() } }

这是一个经典的多态案例:迭代基类。

我想实现这种行为。我知道它多态,但是我是否忽略了实现这种行为的其他“模式”,或者我应该研究 Javascript 中的继承可能性?

【问题讨论】:

    标签: javascript inheritance polymorphism


    【解决方案1】:

    如前所述,JavaScript 是一种基于原型继承的动态类型语言,因此您不能真正使用与类型语言相同的方法。你写的 JS 版本可能是:

    function Shape(){
      throw new Error("Abstract class")
    }
    
    Shape.prototype.printSurface = function () {
      throw new Error ("Not implemented");
    }
    
    function Rect() {
      // constructor;
    }
    
    Rect.prototype = Object.create(Shape.prototype);
    Rect.prototype.printSurface = function() {
      // Rect implementation
    }
    
    function Circle() {
      // constructor;
    }
    
    Circle.prototype = Object.create(Shape.prototype);
    Circle.prototype.printSurface = function() {
      // Circle implementation
    }
    

    然后,在您的应用中:

    var obj = new Circle();
    
    if (obj instanceof Shape) {
        // do something with a shape object
    }
    

    或者,用鸭子打字:

    if ("printSurface" in obj)
        obj.printSurface();
    
    // or
    
    if (obj.printSurface)
        obj.printSurface();
    
    // or a more specific check
    if (typeof obj.printSurface === "function")
        obj.printSurface();
    

    你也有Shape作为没有任何构造函数的对象,它更像是“抽象类”:

    var Shape = {
        printSurface : function () {
            throw new Error ("Not implemented");
        }
    }
    
    function Rect() {
      // constructor;
    }
    
    Rect.prototype = Object.create(Shape);
    Rect.prototype.printSurface = function() {
      // Rect implementation
    }
    
    function Circle() {
      // constructor;
    }
    
    Circle.prototype = Object.create(Shape);
    Circle.prototype.printSurface = function() {
      // Circle implementation
    }
    

    请注意,在这种情况下,您不能再使用 instanceof,因此,或者您回退到鸭式输入,或者您必须使用 isPrototypeOf,但仅在最近的浏览器中可用:

    if (Shape.isPrototypeOf(obj)) {
        // do something with obj
    }
    

    Object.create 在未实现 ES5 规范的浏览器中不可用,但您可以轻松使用 polyfill(请参阅链接)。

    【讨论】:

    • Tx,非常好的答案。但务实地说,我会选择 JOOSE,类框架。
    • 这不适用于文档。我想创建继承自 Document 的 NMLDocument,但出现了一个奇怪的 [LenientThis] 错误。
    【解决方案2】:

    在另一个注意事项上。如果您想使用类以 OO 风格编写 Javascript,您可以查看 Javascript 的许多“类系统”。一个例子是 Joose (http://joose.it)。

    许多客户端框架实现了自己的类系统。 ExtJS 就是一个例子。

    【讨论】:

    • 现在试试,真的很不错
    • 或者只是忘记类并拥抱对象。
    【解决方案3】:

    正如 Weston 所说,如果您不需要继承,那么 Javascript 等动态语言的鸭子类型特性为您提供多态性,因为语言本身不需要强类型基类或接口.

    如果您确实想使用继承并轻松地调用超类的实现,那么可以使用原型或对象字面量来实现,如 Joeseph 所示。

    另一件事是查看Coffescript,因为它可以编译为Javascript,以简单的语法为您提供所有面向对象的优点。它将为您编写所有的样板原型。缺点是它增加了这个额外的编译步骤。也就是说,像上面的示例一样编写一个简单的类层次结构,然后查看结果弹出的 javascript 有助于说明如何完成所有操作。

    【讨论】:

      【解决方案4】:

      我知道这可以用 prototypes 来完成,但我不是使用它的大师。 i prefer the object literal approach(更易于可视化并具有“私有”范围)

      //shape class
      var shape = function() {
          //return an object which "shape" represents
          return {
              printSurface: function() {
                  alert('blank');
              },
              toInherit: function() {
                  alert('inherited from shape');
              }
          }
      };
      
      //rect class
      var rect = function() {
          //inherit shape
          var rectObj = shape();
      
          //private variable
          var imPrivate = 'Arrr, i have been found by getter!';
      
          //override shape's function
          rectObj.printSurface = function(msg) {
              alert('surface of rect is ' + msg);
          }
      
          //you can add functions too
          rectObj.newfunction = function() {
              alert('i was added in rect');
          }
      
          //getters and setters for private stuff work too
          rectObj.newGetter = function(){
              return imPrivate;
          }
      
          //return the object which represents your rectangle
          return rectObj;
      }
      
      
      
      //new rectangle
      var myrect = rect();
      
      //this is the overridden function
      myrect.printSurface('foo');
      
      //the appended function
      myrect.newfunction();
      
      //inherited function
      myrect.toInherit();
      
      //testing the getter
      alert(myrect.newGetter());
      

      【讨论】:

      • 我必须稍后再看,但总是为谁努力提供代码示例 +1!
      • @Weston :这还不足以作为单独的答案吗?框架可以在那里讨论。现在:性能损失总是可以接受的吗?
      【解决方案5】:

      这里的“模式”是“界面”。只要myshapes集合中的所有对象都实现printSurface()方法,就可以了。

      由于 Javascript 是一种动态类型语言,所以集合中的对象根本不需要关联。

      【讨论】:

      • 即使我使用的相同示例也显示在此处:knol.google.com/k/…
      • 我不明白为什么这个答案没有得到更多的支持。它指出了关于 JavaScript 的简单事实,即多态性只是将属性命名为相同。无需担心任何类型约束。
      猜你喜欢
      • 1970-01-01
      • 2013-08-10
      • 1970-01-01
      • 1970-01-01
      • 2010-10-06
      • 1970-01-01
      • 2016-07-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多