2015-07-03 9 views
6

Ich habe einige Probleme bei der Entschlüsselung prototypischen Vererbung in JavaScript, und dachte daran, es hier zu buchen. Betrachten Sie dieses einfache Beispiel:Was ist die Notwendigkeit für Call() in prototypischen Vererbung

function Employee() { 
    this.name = "Rob"; 
    this.dept = "R&D"; 
} 

function Manager() { 
    //Employee.call(this); 
    this.reports = ["Report 1", "Report 2", "Report 3"]; 
} 

Manager.prototype = Object.create(Employee.prototype); 

Employee.prototype.type = "human"; 
m = new Manager(); 
console.log(m.name); //undefined 
console.log(m.type); //human 

Was kann ich nicht verstehen, ist die Nützlichkeit der Linie Employee.call(this). Da wir Employee.protoype als Prototyp des Managers festlegen, muss ich (wie ich es sehe) explizit die Erstellung von Variablen in Employee durch call() erzwingen. Früher dachte ich, dass es sein könnte, weil kein Objekt von Employee existiert, und JS-Vererbung kann nicht ohne Objekte funktionieren, so diente call() hier zum "Vervollständigen des Objekt Build". Aber dann wird die type Eigenschaft in Manager ohne die Notwendigkeit call() widergespiegelt, was beweist, dass wir kein hartes Objekt benötigen, um Vererbung durchzuführen (was ich meine, ist nur die klassenähnliche Konstruktorfunktionsdefinition).

Ich hoffe, ich habe es nicht zu kompliziert gemacht. Kurz gesagt: Warum wird hier call() benötigt, und warum funktioniert die Eigenschaft type ohne call() (wenn call() ist das wichtig, das ist).

Antwort

2

Der Zweck von Employee.call(this) ist das Hinzufügen von Namen und Abteilungsattributen zu Manager-Instanzen.

Die Verwendung von call() ist mehr durch Konvention und ermöglicht es, den Anrufer (dies) an Ort und Stelle zu ändern.

Die Eigenschaft type funktionierte, seit Sie durch die Prototypschnittstelle gingen.

Wenn Sie die Employee.call(this) auskommentieren, wird m.name zu 'Rob'.

+0

"Der Zweck von Employee.call (this) besteht darin, Manager-Instanzen Namen und Abteilungsattribute hinzuzufügen." Was ist dann? Manager.prototype = Object.create (Employee.prototype); Warum führt es nicht dazu, diese Werte zu erben? "Die Verwendung von call() ist mehr Konvention und erlaubt es, den Anrufer (dies) an Ort und Stelle zu ändern." Ich weiß was, aber warum ist es nötig? In der Vererbung sprechen wir über Klassen und Baupläne (ich hoffe) nicht Objekte.Vielleicht geht es mir eher um die Philosophie des Sprachdesigns, aber einige tiefere Antworten wären hilfreicher. – dotslash

+1

Die Object.create() kopiert nur über die Prototypen. Die Eigenschaften name und dept befinden sich nicht im Prototyp, sondern im Konstruktor und werden daher nicht automatisch kopiert. Wenn Sie Manager.prototype = Object.create (Employee) aufrufen, werden 'name' und 'dept' ebenfalls kopiert, aber die Verwendung von call dafür ist weiter verbreitet. – Shilly

+1

@dotslash tatsächlich, es gibt keine Klassen in JavaScript (auch wenn EcmaScript 6 Sie glauben lässt). Es gibt nur Objekte, die an andere Objekte delegieren. Die Arbeit mit dem "neuen" Operator täuscht nur eine pseudoklassische Vererbung vor. Aber es funktioniert nicht, wie Javascript auf der Innenseite funktioniert. Der folgende Beitrag von Eric Elliott könnte helfen, Dinge zu klären: https://medium.com/javascript-scene/common-misconceptions-about-inheritance-in-javascript-d5d9bab29b0a – nils

1

Obwohl der Prototyp vererbt ist, wo der Typ 'Mensch' definiert ist, initiieren Sie die Klasse 'Basis' nicht und führen den Code im Konstruktor aus. Nur weil Employee der Prototyp von Manager ist, können Sie nicht garantieren, dass Sie den Employee-Konstruktor beim Erstellen eines Managers ausführen möchten.

Im Gegensatz zu einigen Sprachen, in denen Sie super() aufrufen können, müssen Sie den Initialisierer für die Basisklasse namentlich aufrufen. Dies ist vergleichbar mit C++:

class Manager : public Employee { 
public: 
    Manager() : Employee() {} 
}; 

Sie erhalten auch zu entscheiden, wenn die Eltern anrufen und zusätzliche Logik durchzuführen, wo ein automatischer Anruf würden Sie diese Möglichkeit nicht geben:

function Employee(name) { 
    this.name = name; 
    this.dept = "R&D"; 
} 

function Manager(name) { 
    // Add the title to the name, first 
    var mgrName = name + ' (Manager)'; 

    Employee.call(this, mgrName); 
    this.reports = ["Report 1", "Report 2", "Report 3"]; 
} 

Manager.prototype = Object.create(Employee.prototype); 
m = new Manager('Bill'); 
0

Die .type (und andere prototypisch vererbte Eigenschaften) funktionieren, ja.
Aber .name und .dept nicht, sie wurden nicht auf m erstellt! Sie hatten recht, die Employee.call(this) wird für eine vollständige Initialisierung benötigt. Es ist der super Aufruf des Konstruktors, den Sie nicht weglassen sollten.

Verwandte Themen