Was ist Polymorphismus in Javascript?

90

Ich habe einen möglichen Artikel über Polymorphismus gelesen, den ich im Internet finden konnte . Aber ich glaube, ich konnte die Bedeutung und ihre Bedeutung nicht ganz erfassen. Die meisten Artikel sagen nicht, warum es wichtig ist und wie ich polymorphes Verhalten in OOP erreichen kann (natürlich in JavaScript).

Ich kann kein Codebeispiel bereitstellen, da ich nicht weiß, wie ich es implementieren soll. Daher sind meine Fragen unten aufgeführt:

  1. Was ist es?
  2. Warum brauchen wir es?
  3. Wie es funktioniert?
  4. Wie kann ich dieses polymorphe Verhalten in Javascript erreichen?

Ich habe dieses Beispiel. Es ist jedoch leicht verständlich, was aus diesem Code resultieren wird. Es gibt keine klare Vorstellung vom Polymorphismus selbst.

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);
AL-Zami
quelle
Diese Frage ist wahrscheinlich zu weit gefasst, um mit StackOverflow gut zu funktionieren. Das Beste, was wir tun könnten, wäre, Sie mit einer anderen Erklärung des Polymorphismus zu verknüpfen. StackOverflow ist am besten in der Lage, bestimmte Fragen oder Erläuterungen zu einem bestimmten Problem zu beantworten, z. B. "Laut Quelle war Polymorphismus XYZ, aber was bedeutet Y?"
Vitruvius
2
du brauchst es nicht überhaupt. Sie brauchen nicht einmal Klassen in JS, und tatsächlich gibt es viele andere, wohl bessere Paradigmen für die App-Erstellung. apply / call / bind macht Homogenität überflüssig, und mit soft-object können Sie alles an Ihre Bedürfnisse anpassen, ohne es vorab zu dekorieren oder Sonderfälle zu erben.
Dandavis
1
Polymorphismus ist nicht nur mit OO verbunden und hat viele Bedeutungen. Vielleicht möchten Sie diese andere Antwort unter den Fragen Ist Polymorphismus ohne Vererbung möglich lesen lesen .
Edwin Dalorzo
Das Erben erfolgt normalerweise falsch in JavaScript. Das Erstellen einer Instanz von Parent, die als Prototyp von Child verwendet werden soll, zeigt ein Unverständnis über die Rolle, die die Konstruktorfunktion und der Prototyp beim Definieren und Erstellen eines Objekts spielen. Weitere Informationen finden Sie in dieser Antwort: stackoverflow.com/a/16063711/1641941
HMR

Antworten:

98

Polymorphismus ist einer der Grundsätze der objektorientierten Programmierung (OOP). Es ist die Praxis, Objekte so zu entwerfen, dass sie Verhaltensweisen gemeinsam nutzen und gemeinsame Verhaltensweisen mit bestimmten überschreiben können. Der Polymorphismus nutzt die Vererbung, um dies zu erreichen.

In OOP wird alles als Objekt betrachtet. Diese Abstraktion kann bis hin zu Schrauben und Muttern für ein Auto oder so breit wie einfach ein Autotyp mit einem Jahr, einer Marke und einem Modell reichen.

Um ein polymorphes Autoszenario zu haben, würde es den Basiswagentyp geben, und dann würde es Unterklassen geben, die vom Auto erben und ihr eigenes Verhalten zusätzlich zu den grundlegenden Verhaltensweisen eines Autos bereitstellen würden. Zum Beispiel könnte eine Unterklasse TowTruck sein, die noch ein Jahr Marke und Modell haben würde, aber auch einige zusätzliche Verhaltensweisen und Eigenschaften haben könnte, die so grundlegend wie eine Flagge für IsTowing sein könnten, so kompliziert wie die Besonderheiten des Aufzugs.

Zurück zum Beispiel von Menschen und Mitarbeitern: Alle Mitarbeiter sind Menschen, aber alle Menschen sind keine Mitarbeiter. Das heißt, dass die Leute die Superklasse und die Mitarbeiter die Unterklasse sein werden. Menschen können Alter und Gewichte haben, aber sie haben keine Gehälter. Mitarbeiter sind Menschen, daher haben sie von Natur aus ein Alter und ein Gewicht, aber auch, weil sie Mitarbeiter sind, haben sie ein Gehalt.

Um dies zu erleichtern, werden wir zuerst die Superklasse (Person) aufschreiben.

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

Und wir geben Person die Möglichkeit, ihre Informationen zu teilen

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

Als nächstes möchten wir eine Unterklasse von Person, Mitarbeiter haben

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

Und wir werden das Verhalten von getInfo überschreiben, indem wir eines definieren, das besser zu einem Mitarbeiter passt

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

Diese können ähnlich wie Ihre ursprüngliche Codeverwendung verwendet werden

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

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

Mit der Vererbung wird hier jedoch nicht viel gewonnen, da der Konstruktor des Mitarbeiters dem der Person so ähnlich ist und die einzige Funktion im Prototyp überschrieben wird. Die Kraft des polymorphen Designs besteht darin, Verhaltensweisen zu teilen.

Travis J.
quelle
2
@ user3138436 - Das ist richtig. Die prototypische Kette wird auf das erste Auftreten überprüft, bei dem es sich um die des getInfoMitarbeiters handelt, da sie in der Kette höher ist als die der Person. Das habe ich gemeint, als ich "überschrieben" sagte.
Travis J
16
Sie verwenden den Konstruktor (Person.call (this, arg)) nicht erneut und setzen den Employee-Prototyp auf eine Instanz von Person. Beim Prototyp werden gemeinsam genutzte Mitglieder verwendet, und bei der Konstruktorfunktion werden die instanzspezifischen Mitglieder erstellt. Ihre Beispiele verwenden Copy-Paste-Code zur Wiederverwendung der Konstruktorfunktion und erben den Prototyp-Teil falsch (Person hat instanzspezifische Mitglieder, die nichts mit Employee.prototype zu tun haben, insbesondere wenn Sie veränderbare Mitglieder haben). Weitere Informationen zur Vererbung mithilfe von Konstruktorfunktionen und Prototypen finden Sie hier: stackoverflow.com/a/16063711/1641941
HMR
3
Damit der Mitarbeiter getinfo der Person wiederverwenden und erweitern kann, kann dies einfach erfolgen, return Person.prototype.getInfo.call(this) + + "and earns " + this.salary + " dollar.";anstatt den Code erneut zu kopieren und einzufügen .
HMR
3
Hier, wo Polymorphismus angewendet wurde?
Albert Jegani
2
@rpeg Der Punkt des Polymorphismus ist im OP-Beispiel besser zu sehen. die Funktion showInfo (); akzeptiert ein allgemeines Objekt. Polymorphismus ist nun die Fähigkeit, je nach Objekttyp unterschiedlich zu reagieren. Ich denke, diese Antwort macht dies nicht klar genug, da sie getInfo () für jedes bestimmte Objekt aufruft.
Stefan
26

Wie in dieser anderen Antwort erläutert , hat der Polymorphismus unterschiedliche Interpretationen.

Die beste Erklärung zu diesem Thema, die ich je gelesen habe, ist ein Artikel von Luca Cardelli , einem bekannten Typentheoretiker. Der Artikel heißt Über das Verständnis von Typen, Datenabstraktion und Polymorphismus .

Was ist es?

Cardelli definiert in diesem Artikel verschiedene Arten von Polymorphismus:

  • Universal
    • parametrisch
    • Aufnahme
  • Ad hoc
    • oveloading
    • Zwang

Vielleicht ist es in JavaScript etwas schwieriger, die Auswirkungen des Polymorphismus zu erkennen, da die klassischeren Arten des Polymorphismus in statischen Typsystemen offensichtlicher sind, während JavaScript ein dynamisches Typsystem aufweist.

So gibt es beispielsweise zur Kompilierungszeit in JavaScript keine Methoden- oder Funktionsüberladung oder automatische Typzwänge. In einer dynamischen Sprache halten wir die meisten dieser Dinge für selbstverständlich. Aufgrund der Dynamik der Sprache benötigen wir in JavaScript auch keinen parametrischen Polymorphismus.

Dennoch hat JavaScript eine Form der Typvererbung, die dieselben Ideen des Subtyp-Polymorphismus (von Cardelli oben als Einschlusspolymorphismus klassifiziert) emuliert, ähnlich wie wir es normalerweise in anderen objektorientierten Programmiersprachen wie Java oder C # tun (wie in erläutert) eine andere Antwort, die ich oben geteilt habe).

Eine andere Form des Polymorphismus, die in dynamischen Sprachen sehr typisch ist, heißt Ententypisierung .

Es ist ein Fehler zu glauben, dass Polymorphismus nur mit objektorientierter Programmierung zusammenhängt. Andere Programmiermodelle (funktional, prozedural, logisch usw.) bieten unterschiedliche Formen des Polymorphismus in ihren Typsystemen, wahrscheinlich auf eine Weise, die denen, die nur für OOP verwendet werden, etwas unbekannt ist.

Warum brauchen wir es?

Polymorphismus fördert viele gute Eigenschaften von Software, fördert unter anderem die Modularität und Wiederverwendbarkeit und macht das Typensystem flexibler und formbarer. Ohne sie wäre es wirklich schwierig, über Typen nachzudenken. Durch Polymorphismus wird sichergestellt, dass ein Typ durch andere kompatible ersetzt werden kann, sofern diese eine öffentliche Schnittstelle erfüllen. Dies fördert auch das Ausblenden von Informationen und die Modularität.

Wie funktioniert es?

Dies ist nicht einfach zu beantworten, verschiedene Sprachen haben unterschiedliche Möglichkeiten, es zu implementieren. Im Fall von JavaScript wird es, wie oben erwähnt, in Form von Typhierarchien mithilfe der prototypischen Vererbung angezeigt, und Sie können es auch mithilfe der Ententypisierung ausnutzen.

Das Thema ist etwas weit gefasst und Sie haben zwei viele Fragen in einem einzigen Beitrag geöffnet. Vielleicht ist es am besten, wenn Sie zuerst Cardellis Artikel lesen und dann versuchen, den Polymorphismus unabhängig von einer Sprache oder einem Programmierparadigma zu verstehen. Dann werden Sie Assoziationen zwischen den theoretischen Konzepten und dem herstellen, was eine bestimmte Sprache wie JavaScript zu bieten hat, um diese Ideen umzusetzen.

Edwin Dalorzo
quelle
14

Was ist der Zweck des Polymorphismus?

Durch Polymorphismus wird ein statisches Typsystem flexibler, ohne die (signifikante) Sicherheit des statischen Typs zu verlieren, indem die Bedingungen für die Typäquivalenz gelockert werden. Der Beweis bleibt, dass ein Programm nur ausgeführt wird, wenn es keine Typfehler enthält.

Eine polymorphe Funktion oder ein Datentyp ist allgemeiner als eine monomorphe, da sie in einem breiteren Spektrum von Szenarien verwendet werden kann. In diesem Sinne repräsentiert Polymorphismus die Idee der Verallgemeinerung in streng typisierten Sprachen.

Wie trifft dies auf Javascript zu?

Javascript hat ein schwaches, dynamisches Typsystem. Ein solches Typsystem entspricht einem strengen Typsystem, das nur einen Typ enthält. Wir können uns einen solchen Typ als einen riesigen Unionstyp vorstellen (Pseudosyntax):

type T =
 | Undefined
 | Null
 | Number
 | String
 | Boolean
 | Symbol
 | Object
 | Array
 | Map
 | ...

Jeder Wert wird zur Laufzeit einer dieser Typalternativen zugeordnet. Und da Javascript schwach typisiert ist, kann jeder Wert seinen Typ beliebig oft ändern.

Wenn wir eine typentheoretische Perspektive einnehmen und bedenken, dass es nur einen Typ gibt, können wir mit Sicherheit sagen, dass das Typensystem von Javascript keinen Begriff von Polymorphismus hat. Stattdessen haben wir Ententypisierung und impliziten Typzwang.

Dies sollte uns jedoch nicht davon abhalten, über Typen in unseren Programmen nachzudenken. Aufgrund des Fehlens von Typen in Javascript müssen wir diese während des Codierungsprozesses ableiten. Unser Verstand muss für den fehlenden Compiler eintreten, dh sobald wir uns ein Programm ansehen, müssen wir nicht nur die Algorithmen, sondern auch die zugrunde liegenden (möglicherweise polymorphen) Typen erkennen. Diese Typen helfen uns, zuverlässigere und robustere Programme zu erstellen.

Um dies richtig zu machen, werde ich Ihnen einen Überblick über die häufigsten Manifestationen des Polymorphismus geben.

Parametrischer Polymorphismus (auch bekannt als Generika)

Der parametrische Polymorphismus besagt, dass verschiedene Typen austauschbar sind, da Typen überhaupt keine Rolle spielen. Eine Funktion, die einen oder mehrere Parameter vom parametrischen polymorphen Typ definiert, darf nichts über die entsprechenden Argumente wissen, sondern sie alle gleich behandeln, da sie für jeden Typ übernommen werden können. Dies ist ziemlich einschränkend, da eine solche Funktion nur mit den Eigenschaften ihrer Argumente arbeiten kann, die nicht Teil ihrer Daten sind:

// parametric polymorphic functions

const id = x => x;

id(1); // 1
id("foo"); // "foo"

const k = x => y => x;
const k_ = x => y => y;

k(1) ("foo"); // 1
k_(1) ("foo"); // "foo"

const append = x => xs => xs.concat([x]);

append(3) ([1, 2]); // [1, 2, 3]
append("c") (["a", "b"]); // ["a", "b", "c"]

Ad-hoc-Polymorphismus (auch bekannt als Überladung)

Ad-hoc-Polymorphismus besagt, dass verschiedene Typen nur für einen bestimmten Zweck gleichwertig sind. Um in diesem Sinne gleichwertig zu sein, muss ein Typ eine Reihe von Funktionen implementieren, die für diesen Zweck spezifisch sind. Eine Funktion, die einen oder mehrere Parameter vom polymorphen Ad-hoc-Typ definiert, muss dann wissen, welche Funktionssätze jedem ihrer Argumente zugeordnet sind.

Ad-hoc-Polymorphismus macht eine Funktion mit einer größeren Domäne von Typen kompatibel. Das folgende Beispiel zeigt den Zweck der "Zuordnung" und wie Typen diese Einschränkung implementieren können. Anstelle eines Funktionssatzes enthält die "abbildbare" Einschränkung nur eine einzige mapFunktion:

// Option type
class Option {
  cata(pattern, option) {
    return pattern[option.constructor.name](option.x);
  }
  
  map(f, opt) {
    return this.cata({Some: x => new Some(f(x)), None: () => this}, opt);
  }
};

class Some extends Option {
  constructor(x) {
    super(x);
    this.x = x;
  }
};

class None extends Option {
  constructor() {
    super();
  }
};


// ad-hoc polymorphic function
const map = f => t => t.map(f, t);

// helper/data

const sqr = x => x * x;

const xs = [1, 2, 3];
const x = new Some(5);
const y = new None();

// application

console.log(
  map(sqr) (xs) // [1, 4, 9]
);

console.log(
  map(sqr) (x) // Some {x: 25}
);

console.log(
  map(sqr) (y) // None {}
);

Subtyp-Polymorphismus

Da andere Antworten bereits den Subtyp-Polymorphismus abdecken, überspringe ich ihn.

Struktureller Polymorphismus (auch bekannt als strutruale Subtypisierung)

Struktureller Polymorphismus besagt, dass verschiedene Typen äquivalent sind, wenn sie dieselbe Struktur so enthalten, dass ein Typ alle Eigenschaften des anderen hat, aber zusätzliche Eigenschaften enthalten kann. Abgesehen davon ist struktureller Polymorphismus Ententypisierung zur Kompilierungszeit und bietet sicherlich zusätzliche Typensicherheit. Indem jedoch behauptet wird, dass zwei Werte vom gleichen Typ sind, nur weil sie einige Eigenschaften gemeinsam haben, wird die semantische Wertebene vollständig ignoriert:

const weight = {value: 90, foo: true};
const speed =  {value: 90, foo: false, bar: [1, 2, 3]};

Leider speedwird dies als Subtyp von angesehen weightund sobald wir die valueEigenschaften vergleichen, vergleichen wir Äpfel virtuell mit Orangen.


quelle
1
Dies ist zwar in vielerlei Hinsicht genauer (und sicherlich gründlicher) als die akzeptierte Antwort, hat jedoch nicht die gleiche Zugänglichkeit: Diese Antwort setzt voraus, dass der Fragesteller bereits zu klug ist, um sich mit der Frage zu befassen :)
Jared Smith
@JaredSmith Ich habe versucht, das Thema auf einige leicht verständliche Absätze zu reduzieren. Aber je tiefer ich bohre, desto komplexer wird es. Ich habe nie eine gute Quelle für Polymorphismus in untypisierten Sprachen gefunden, daher halte ich diese Antwort dennoch für wertvoll.
Die Bearbeitung verbessert die Zugänglichkeit erheblich. Was die Nützlichkeit des Polymorphismus in dynamischen Sprachen betrifft, gibt es viele, aber ich habe Mühe, mir ein gutes Beispiel für JS vorzustellen. Ein besseres Beispiel wären Pythons magische Methoden, mit denen benutzerdefinierte Typen mit polymorphen Funktionen wie arbeiten können len. Oder vielleicht conjaus Clojure.
Jared Smith
8

Was ist es?

Poly = viele, Morphismus = Form- oder Verhaltensänderung.

warum brauchen wir es

Bei der Programmierung wird es verwendet, wenn die Schnittstelle einer Funktion (z. B. Funktion X) flexibel genug sein soll, um unterschiedliche Typen oder Anzahl von Parametern zu akzeptieren. Basierend auf der Änderung von Parametertypen oder -zahlen möchten wir möglicherweise, dass sich die Funktion X anders verhält (Morphismus).

Wie es funktioniert?

Wir schreiben mehrere Implementierungen der X-Funktion, wobei jede Implementierung unterschiedliche Parametertypen oder die Anzahl der Parameter akzeptiert. Basierend auf dem Typ oder der Anzahl der Parameter entscheidet der Compiler (zur Laufzeit), welche Implementierung von X ausgeführt werden soll, wenn X aus einem Code aufgerufen wird.

Wie kann ich dieses polymorphe Verhalten in Javascript erreichen?

JS ist keine typisierte Sprache, daher sollte es keine OOP-Konzepte wie Polymorphismus verwenden. Die neuere Version von JS enthält jetzt jedoch Klassen, und es besteht die Möglichkeit, dass Polymosphismus auch in JS Sinn macht. Andere Antworten bieten einige interessante Problemumgehungen.

Hadaytullah
quelle
3

Polymorphismus bedeutet, dass die Fähigkeit, dieselbe Methode für verschiedene Objekte aufzurufen und jedes Objekt auf unterschiedliche Weise reagiert, als POLYMORPHISMUS bezeichnet wird .

    function Animal(sound){
    this.sound=sound;
    this.speak=function(){
    			return this.sound;
    	}
    }
//one method 
    function showInfo(obj){
    		console.log(obj.speak());
    }
//different objects
    var dog = new Animal("woof");
    var cat = new Animal("meow");
    var cow = new Animal("humbow");
//responds different ways
    showInfo(dog);
    showInfo(cat);
    showInfo(cow);

SooRaj Patil
quelle
2

JavaScript ist eine interpretierte Sprache, keine kompilierte Sprache.

Kompilierungszeit-Polymorhismus (oder statischer Polymorphismus) Der Kompilierungszeit-Polymorphismus ist nichts anderes als die Methodenüberladung in Java, c ++

Daher ist eine Methodenüberladung in Javascript nicht möglich.

Dynamischer (Laufzeit-) Polymorphismus ist jedoch der zur Laufzeit vorhandene Polymorphismus, sodass das Überschreiben von Methoden in Javascript möglich ist

Ein weiteres Beispiel ist PHP.

Apoorv
quelle