162

Ich bin neu in JavaScript OOP. Können Sie den Unterschied zwischen den folgenden Code-Blöcken erklären? Ich habe getestet und beide Blöcke funktionieren. Was ist die beste Praxis und warum?Vererbung der prototypischen Vererbung in JavaScript

Erster Block:

function Car(name){ 
    this.Name = name; 
} 

Car.prototype.Drive = function(){ 
    document.write("My name is " + this.Name + " and I'm driving. <br />"); 
} 

SuperCar.prototype = new Car(); 
SuperCar.prototype.constructor = SuperCar; 

function SuperCar(name){ 
    Car.call(this, name); 
} 

SuperCar.prototype.Fly = function(){ 
    document.write("My name is " + this.Name + " and I'm flying! <br />"); 
} 

var myCar = new Car("Car"); 
myCar.Drive(); 

var mySuperCar = new SuperCar("SuperCar"); 
mySuperCar.Drive(); 
mySuperCar.Fly(); 

Zweiter Block:

function Car(name){ 
    this.Name = name; 
    this.Drive = function(){ 
     document.write("My name is " + this.Name + " and I'm driving. <br />"); 
    } 
} 

SuperCar.prototype = new Car(); 

function SuperCar(name){ 
    Car.call(this, name); 
    this.Fly = function(){ 
     document.write("My name is " + this.Name + " and I'm flying! <br />"); 
    } 
} 

var myCar = new Car("Car"); 
myCar.Drive(); 

var mySuperCar = new SuperCar("SuperCar"); 
mySuperCar.Drive(); 
mySuperCar.Fly(); 

Warum der Autor Drive und Fly Methoden nicht hinzugefügt prototype verwenden, aber nicht erklären, sie nicht als this.Drive Methode innerhalb Car Klasse und this.Fly in SuperCar Klasse?

Warum muss SuperCar.prototype.constructor auf SuperCar zurückgesetzt werden? Wird die Konstruktoreigenschaft überschrieben, wenn prototype festgelegt ist? Ich habe diese Zeile auskommentiert und nichts hat sich geändert.

Warum Car.call(this, name); in SuperCar Konstruktor aufrufen? Werden nicht die Eigenschaften und Methoden von Car ‚geerbt‘, wenn ich

var myCar = new Car("Car"); 
+3

Die moderneren Weg zu Object.create verwenden () statt neu: http://ncombo.wordpress.com/2013/07/11/javascript-inheritance-done-right/ – Jon

+2

Nur eine Anmerkung dieses Beispiel kann verwirrend sein: "Super" bezieht sich in diesem Fall auf ein fliegendes Auto, während "Super" in OOP normalerweise auf den Elternprototyp/Klasse verweist. – mikemaccana

+2

Ich denke, der Teil, der die prototypische Vererbung von JavaScript erschwert, ist, wo es mit einem Konstruktor gemischt wird. Was, wenn wir die Idee des Konstruktors und der Klasse entfernen und wir nur Objekte haben. Jedes Objekt wird entweder von nichts (null) oder von einem anderen Objekt geerbt. Das wird viel einfacher zu verstehen sein, und genau das macht Object.create(). –

Antwort

78

Die beiden Blöcke unterscheiden sich in einer Weise, dass Drive() im ersten Beispiel nur einmal vorhanden sein wird, während bei dem zweiten Ansatz Drive() pro Instanz existieren wird (jedes Mal, wenn Sie new Car() tun, um die Funktion drive() wieder angelegt). Oder anders gesagt, der erste verwendet den Prototyp zum Speichern der Funktion und der zweite den Konstruktor. Das Nachschlagen nach Funktionen ist Konstruktor und dann Prototyp. Also für Ihr Nachschlagen von findet es es unabhängig davon, ob es im Konstruktor oder im Prototyp ist. Die Verwendung des Prototyps ist effizienter, da normalerweise eine Funktion nur einmal pro Typ benötigt wird.

Die new Aufruf in Javascript setzt automatisch den Konstruktor im Prototyp. Wenn Sie den Prototyp überschreiben, müssen Sie den Konstruktor manuell festlegen.

Vererbung in Javascript hat nichts wie super. Wenn Sie also eine Unterklasse haben, ist die einzige Möglichkeit, den Superkonstruktor aufzurufen, der Name.

1

tun bin ich nicht 100% sicher, aber ich glaube, der Unterschied ist, dass das zweite Beispiel einfach den Inhalt der Car-Klasse in die SuperCar dupliziert Objekt, während der erste verbindet den SuperCar-Prototyp mit der Car-Klasse, so dass Laufzeitänderungen an der Car-Klasse auch die SuperCar-Klasse beeinflussen.

136

Um zu Norbert Hartl's answer hinzuzufügen, wird SuperCar.prototype.constructor nicht benötigt, aber einige Leute verwenden es als eine bequeme Möglichkeit, die Konstruktionsfunktion eines Objekts zu erhalten (in diesem Fall SuperCar-Objekte).

gerade von dem ersten Beispiel Car.call (this, Name) in der SuperCar Konstruktorfunktion, weil, wenn Sie dies tun:

var mySuperCar = new SuperCar("SuperCar"); 

Dies ist, was JavaScript tut:

  1. A frisches, leeres Objekt wird instanziiert.
  2. Der interne Prototyp des neuen Objekts wird auf Auto festgelegt.
  3. Die SuperCar-Konstruktorfunktion wird ausgeführt.
  4. Das fertige Objekt wird zurückgegeben und in mySuperCar festgelegt.

Beachten Sie, wie JavaScript Auto für Sie nicht aufgerufen hat. Prototypen, so wie sie sind, jede Eigenschaft oder Methode, die Sie nicht selbst für SuperCar festlegen, werden in Auto nachgeschlagen. Manchmal ist das gut, z.B. SuperCar verfügt nicht über eine Drive-Methode, aber es kann Cars eins gemeinsam nutzen, sodass alle SuperCars die gleiche Drive-Methode verwenden. Andere Zeiten, die Sie nicht teilen möchten, wie jeder SuperCar seinen eigenen Namen hat. Wie geht man also, um den Namen eines jeden SuperCars zu einem eigenen Ding zu machen? Sie könnten this.Name innerhalb der SuperCar Konstruktor-Funktion eingestellt:

function SuperCar(name){ 
    this.Name = name; 
} 

Dies funktioniert, aber eine Sekunde warten. Haben wir im Auto-Konstruktor nicht genau dasselbe gemacht? Ich will mich nicht wiederholen. Da Car den Namen bereits vergeben hat, nennen wir es einfach.

function SuperCar(name){ 
    this = Car(name); 
} 

Whoops, Sie wollen nie den besonderen this Objektverweis ändern. Erinnere dich an die 4 Schritte? Halte dich an das Objekt, das dir JavaScript gegeben hat, denn nur so kannst du die wertvolle interne Prototypverbindung zwischen deinem SuperCar-Objekt und Car erhalten. Wie setzen wir den Namen, ohne uns zu wiederholen und ohne unser neues SuperCar-Objekt wegzuwerfen? JavaScript hat sich so viel Mühe gegeben, uns vorzubereiten?

Zwei Dinge. One: die Bedeutung von this ist flexibel. Zweitens: Auto ist eine Funktion. Es ist möglich, Car aufzurufen, nicht mit einem makellosen, instanziierten Objekt, sondern mit einem SuperCar-Objekt. Das gibt uns die endgültige Lösung, die einen Teil des ersten Beispiels in Ihrer Frage ist:

function SuperCar(name){ 
    Car.call(this, name); 
} 

Als Funktion, Fahrzeug erlaubt mit der call method der Funktion aufgerufen werden, was die Bedeutung von this innerhalb Car auf die Veränderungen SuperCar-Instanz bauen wir auf. Presto! Jetzt erhält jeder SuperCar seine eigene Name-Eigenschaft.

Zum Abschluss gibt Car.call(this, name) im SuperCar-Konstruktor jedem neuen SuperCar-Objekt seine eigene eindeutige Name-Eigenschaft, ohne jedoch den bereits in Auto vorhandenen Code zu duplizieren.

Prototypen sind nicht gruselig, wenn man sie erst einmal verstanden hat, aber sie sind dem klassischen Klasse/Vererbungs-OOP-Modell überhaupt nicht sehr ähnlich. Ich schrieb einen Artikel über the prototypes concept in JavaScript. Es ist für eine Spielengine geschrieben, die JavaScript verwendet, aber es ist die gleiche JavaScript-Engine, die von Firefox verwendet wird, also sollte alles relevant sein. Hoffe das hilft.

+4

"SuperCar.prototype.constructor" wird benötigt, wenn Sie wollen Object.getPrototypeOf emuliert in älteren Engines zu arbeiten – Raynos

+3

Der aktuelle Link zu "das Prototyp-Konzept in Javascript" ist gebrochen. Gibt es einen anderen Ort, an dem ich diesen Artikel lesen kann? – shockawave123

8

Norbert, Sie sollten beachten, dass Ihr erstes Beispiel ziemlich genau das ist, was Douglas Crockford pseudoklassische Vererbung nennt. Etwas Dinge darüber zu beachten:

  1. Sie das Auto Konstruktor rufen zweimal, einmal von der SuperCar.prototype = new Auto() Linie und der anderen aus der „Konstruktor Stehlen“ Linie Car.call (dies .. .Sie können stattdessen eine Hilfsmethode erstellen, um Prototypen zu erben, und Ihr Car-Konstruktor muss nur einmal ausgeführt werden, um die Einrichtung effizienter zu machen
  2. Die SuperCar.prototype.constructor = SuperCar-Zeile ermöglicht es Ihnen, mit instanceof den Konstruktor zu identifizieren. Einige Leute wollen, dass andere nur vermeiden, instanceof
  3. Referenz vars wie: var arr = ['one', 'zwei'], wenn auf dem Super definiert (zB Auto) wird von allen Instanzen geteilt werden. Dies bedeutet inst1.arr. Pu sh ['drei'], inst2.arr.push ['vier'] usw. werden für alle Instanzen angezeigt!Im Wesentlichen, statisches Verhalten, das Sie wahrscheinlich nicht wollen.
  4. Ihr zweiter Block definiert die Fly-Methode im Konstruktor. Dies bedeutet, dass für jedes Mal, wenn es aufgerufen wird, ein "Methodenobjekt" erstellt wird. Besser, einen Prototyp für Methoden zu verwenden! Sie können es jedoch im Konstruktor behalten, wenn Sie möchten - Sie müssen nur wachen, damit Sie das Prototyp-Literal nur einmal initialisieren (pseudo): if (SuperCar.prototype.myMethod! = 'Function') ... dann definieren Ihr Prototyp-Literal.
  5. 'Warum Car.call (this, name) ....' anrufen: Ich habe keine Zeit, um Ihren Code genau zu betrachten, damit ich falsch liege, aber das ist normalerweise so, dass jede Instanz ihren eigenen Status behalten kann um das Problem des "statischen" Verhaltens der Prototypverkettung zu beheben, das ich oben beschrieben habe.

Schließlich möchte ich erwähnen, dass ich einige Beispiele für TDD JavaScript Inheritance Code, das funktioniert hier: TDD JavaScript Inheritance Code and Essay Ich würde gerne Ihre Meinung bekommen, wie ich es zu verbessern bin der Hoffnung, und halten es Open Source . Das Ziel ist es, klassischen Programmierern zu helfen, schnell mit JavaScript Schritt zu halten und die Studie sowohl in den Büchern von Crockford als auch Zakas zu ergänzen.

+1

Ich bin schon einmal auf Punkt (1) gestoßen. Ich fand, dass, wenn nicht das neue Schlüsselwort verwendet und nur Superclass.call (this) verwendet wurde (so SuperCar = {Car.call (this);}; SuperCar.prototype = Car;), dass dies zu funktionieren schien. Gibt es einen Grund, dies nicht zu tun? (Entschuldigung für den Nekro) – obie

+0

Aus * klassischen * OOP-Sprachen kommend, habe ich immer * seltsam * die Notwendigkeit gefunden, eine 'neue' Instanz zu erstellen * nur * um die Prototyp-Kette zu füllen – superjos

+0

Schönes Buch. Sie sollten beachten, dass der Link oben auf der GitHub-Seite unterbrochen ist, obwohl er natürlich im Inhalt gefunden werden kann. –

0
function abc() { 
} 

Prototype Methoden und Eigentum für die Funktion abc erstellt

abc.prototype.testProperty = 'Hi, I am prototype property'; 
abc.prototype.testMethod = function() { 
    alert('Hi i am prototype method') 
} 

Erstellen neuer Instanzen für die Funktion abc

var objx = new abc(); 

console.log(objx.testProperty); // will display Hi, I am prototype property 
objx.testMethod();// alert Hi i am prototype method 

var objy = new abc(); 

console.log(objy.testProperty); //will display Hi, I am prototype property 
objy.testProperty = Hi, I am over-ridden prototype property 

console.log(objy.testProperty); //will display Hi, I am over-ridden prototype property 

http://astutejs.blogspot.in/2015/10/javascript-prototype-is-easy.html