我应该在JavaScript中使用多态吗?

32

我是一名程序员,曾经用过多种语言进行编程,包括函数式和面向对象的语言。我也写过一些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中的继承可能性?

5个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
43

正如所说,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 这个类框架。 - Peter
这对于文档不起作用。我想创建一个继承自文档的NMLDocument,但出现了奇怪的[LenientThis]错误。 - m93a

13

这里涉及到的“模式”是“接口”。只要 myshapes 集合中的所有对象都实现了 printSurface() 方法,就没问题。

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


1
即使我使用的相同示例也在这里显示: http://knol.google.com/k/programming-to-the-interface-in-javascript-yes-it-can-be-done-er-i-mean-faked# - Peter
1
我不明白为什么这个回答没有得到更多的赞。它指出了有关JavaScript的简单真相,即多态只是将属性命名相同。没有任何需要担心的类型约束。 - user234932

8

我知道这可以通过使用原型来实现,但我并不是它的大师。 我更喜欢对象字面量方法(更容易可视化和具有“私有”作用域)。

//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! - Peter
1
@Weston:这难道不足以成为一个独立的答案吗?框架可以在那里讨论。现在的问题是:性能损失总是可以接受的吗? - Peter

4
如韦斯顿所说,如果您不需要继承,则动态语言(例如Javascript)的鸭子类型特性会给您带来多态性,因为语言本身没有对强类型基类或接口有要求。 如果您想使用继承并像轻松调用超类实现这样的操作,则可以使用原型或对象字面量来实现,就像Joeseph所展示的那样。 另一件事是看看Coffescript,因为它将编译成Javascript,以简单的语法提供所有的面向对象好处。它将为您编写所有的样板原型内容。缺点是它增加了这个额外的编译步骤。话虽如此,编写一个简单的类层次结构,就像上面的例子,然后查看Javascript输出结果有助于展示如何完成所有这些操作。

4

另外,如果您想使用类以OO风格编写Javascript代码,可以了解一下许多适用于Javascript的“类系统”,其中一个例子是Joose(http://joose.it)。

许多客户端框架实现了自己的类系统,例如ExtJS。


2
现在试一下,真的非常好。 - Peter
或者忘记类,拥抱对象。 - user234932

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,