Javascript 中的多态性是什么?

我读过一些可能的文章,我可以在互联网上找到关于多态性的文章。但我认为我不能完全理解它的含义和重要性。大多数文章都没有说明为什么它很重要,以及我如何在OOP中实现多态行为(当然是在JavaScript中)。

我无法提供任何代码示例,因为我不知道如何实现它,所以我的问题如下:

  1. 这是什么?
  2. 为什么我们需要它?
  3. 它是如何工作的?
  4. 如何在javascript中实现这种多态行为?

我有这个例子。但是很容易理解这个代码的结果是什么。它没有给出任何关于多态性本身的清晰概念。

function Person(age, weight) {
    this.age = age;
    this.weight = weight;
    this.getInfo = function() {
        return "I am " + this.age + " years old " +
        "and weighs " + this.weight +" kilo.";
    }
}
function Employee(age, weight, salary) {
    this.salary = salary;
    this.age = age;
    this.weight = weight;
    this.getInfo = function() {
        return "I am " + this.age + " years old " +
        "and weighs " + this.weight +" kilo " +
        "and earns " + this.salary + " dollar.";
    }
}

Employee.prototype = new Person();
Employee.prototype.constructor = Employee;
  // The argument, 'obj', can be of any kind
  // which method, getInfo(), to be executed depend on the object
  // that 'obj' refer to.

function showInfo(obj) {
    document.write(obj.getInfo() + "<br>");
}

var person = new Person(50,90);
var employee = new Employee(43,80,50000);
showInfo(person);
showInfo(employee);

答案 1

多态性是面向对象编程 (OOP) 的原则之一。将对象设计为共享行为并能够使用特定行为覆盖共享行为的做法。多态性利用继承来实现这一点。

在 OOP 中,所有内容都被视为一个对象建模。这种抽象可以一直归结为汽车的螺母和螺栓,也可以像简单的汽车类型一样广泛,带有年份,品牌和型号。

要有一个多态汽车场景,就会有基本的汽车类型,然后会有子类,这些子类将从汽车继承,并在汽车的基本行为之上提供自己的行为。例如,子类可以是TowTruck,它仍然会有一年的品牌和模型,但也可能有一些额外的行为和属性,这些行为和属性可以像IsTowing的标志一样基本,就像电梯的细节一样复杂。

回到人和员工的例子,所有员工都是人,但所有人都不是员工。也就是说,人将是超班,员工是子类。人们可能有年龄和体重,但他们没有薪水。员工是人,所以他们天生就有年龄和体重,但也因为他们是员工,所以他们会有薪水。

所以为了方便这个,我们先写出超类(人)

function Person(age,weight){
 this.age = age;
 this.weight = weight;
}

我们将赋予个人分享其信息的能力

Person.prototype.getInfo = function(){
 return "I am " + this.age + " years old " +
    "and weighs " + this.weight +" kilo.";
};

接下来,我们希望有一个子类“人员,员工”

function Employee(age,weight,salary){
 this.age = age;
 this.weight = weight;
 this.salary = salary;
}
Employee.prototype = new Person();

我们将通过定义一个更适合员工的getInfo行为来覆盖getInfo的行为。

Employee.prototype.getInfo = function(){
 return "I am " + this.age + " years old " +
    "and weighs " + this.weight +" kilo " +
    "and earns " + this.salary + " dollar.";  
};

这些可以像原始代码一样使用

var person = new Person(50,90);
var employee = new Employee(43,80,50000);

console.log(person.getInfo());
console.log(employee.getInfo());

但是,在这里使用继承并没有多大收获,因为 Employee 的构造函数与 person 的构造函数非常相似,并且原型中唯一的功能是被覆盖。多态设计的力量是共享行为。


答案 2

正如在另一个答案中所解释的那样,多态性有不同的解释。

我读过的关于这个主题的最好的解释是卢卡·卡德利(Luca Cardelli)的一篇文章,他是一位著名的类型理论家。本文名为“了解类型、数据抽象和多态性”。

这是什么?

Cardelli在本文中定义了几种类型的多态性:

  • 普遍
  • 参数
  • 包含
  • 临时
  • oveloading
  • 强迫

也许在JavaScript中,很难看到多态性的影响,因为更经典的多态性类型在静态类型系统中更明显,而JavaScript具有动态类型系统。

因此,例如,在JavaScript中没有方法或函数重载或编译时的自动类型强制。在动态语言中,我们认为这些事情中的大多数都是理所当然的。由于JavaScript的动态性质,我们既不需要在JavaScript中使用参数化多态性。

尽管如此,JavaScript仍然具有一种类型继承形式,它模拟了子类型多态性的相同想法(上面Cardelli将其归类为包含多态性),其方式类似于我们通常在其他面向对象的编程语言(如Java或C#)中所做的(如我上面分享的另一个答案中所述)。

在动态语言中非常典型的另一种形式的多态性称为鸭子类型

认为多态性只与面向对象编程有关是错误的。其他编程模型(函数式、过程式、逻辑等)在其类型系统中提供了不同形式的多态性,对于那些只习惯于OOP的人来说,可能有点陌生。

我们为什么需要它?

多态性在软件中培养了许多良好的属性,其中包括它促进了模块化和可重用性,并使类型系统更加灵活和可塑性。没有它,就很难对类型进行推理。多态性确保一种类型可以被其他兼容的类型所取代,只要它们满足公共接口,因此这也促进了信息隐藏和模块化。

它是如何工作的?

这个问题回答起来并不简单,不同的语言有不同的实现方式。在JavaScript的情况下,如上所述,您将看到它使用原型继承以类型层次结构的形式实现,您也可以使用鸭子类型来利用它。

这个主题有点宽泛,你在一篇文章中打开了太多的问题。也许你最好从阅读Cardelli的论文开始,然后尝试理解多态性,而不管任何语言或编程范式如何,然后你将开始在理论概念和任何特定语言(如JavaScript)必须提供的东西之间建立关联来实现这些想法。