Was ist die Bedeutung der JavaScript-Konstruktoreigenschaft?


Answers

Der erste Schritt besteht darin, zu verstehen, worum es bei constructor und prototype geht. Es ist nicht schwer, aber man muss die "Vererbung" im klassischen Sinne loslassen.

Der Konstruktor

Die constructor verursacht in Ihrem Programm keine bestimmten Effekte, außer dass Sie sie betrachten können, um zu sehen, welche Funktion in Verbindung mit dem Operator new , um Ihr Objekt zu erstellen. Wenn Sie new Bar() eingegeben haben, wird es Bar und Sie eingegebenes new Foo es wird Foo .

Der Prototyp

Die prototype wird für die Suche verwendet, falls das fragliche Objekt nicht die angeforderte Eigenschaft hat. Wenn Sie x.attr schreiben, wird JavaScript versuchen, attr unter den Attributen von x zu finden. Wenn es es nicht finden kann, wird es in x.__proto__ . Wenn es auch nicht vorhanden ist, wird es nach x.__proto__.__proto__ solange __proto__ definiert ist.

Was ist __proto__ und was hat es mit dem prototype zu tun? Kurz gesagt, prototype ist für "Typen", während __proto__ für "Instanzen" ist. (Ich sage das mit Anführungszeichen, weil es keinen Unterschied zwischen Typen und Instanzen gibt). Wenn Sie x = new MyType() schreiben, geschieht unter anderem, dass x.__proto___ auf MyType.prototype .

Die Frage

Nun, das oben Genannte sollte alles sein, was Sie brauchen, um abzuleiten, was Ihr eigenes Beispiel bedeutet, sondern um zu versuchen, Ihre eigentliche Frage zu beantworten; "warum schreibe so etwas wie":

Bar.prototype.constructor = Bar;

Ich persönlich habe es nie gesehen und ich finde es ein wenig albern, aber in dem Kontext, den du angegeben hast, wird es bedeuten, dass das Bar.prototype (erstellt unter Verwendung von new Foo(42) ) so Bar.prototype wird, wie es von Bar erstellt wurde eher als Foo . Ich nehme an, die Idee ist, etwas Ähnliches wie C ++ / Java / C # -ähnliche Sprachen zu machen, wo ein Typ-Lookup (die constructor Eigenschaft) immer den spezifischsten Typ und nicht den Typ des generischen Objekts weiter oben im Prototyp ergibt. Kette.

Mein Tipp: Denken Sie nicht viel über "Vererbung" in JavaScript nach. Die Konzepte von Schnittstellen und Mixins machen mehr Sinn. Und überprüfen Sie keine Objekte auf ihre Typen. Suchen Sie stattdessen nach den erforderlichen Eigenschaften ("wenn es wie eine Ente geht und quakt wie eine Ente, ist es eine Ente").

Der Versuch, JavaScript in ein klassisches Vererbungsmodell zu zwingen, wenn alles, was es hat, der oben beschriebene Prototyp-Mechanismus ist, verursacht die Verwirrung. Die vielen Leute, die vorgeschlagen haben, den constructor -property manuell zu setzen, haben wahrscheinlich genau das versucht. Abstraktionen sind in Ordnung, aber diese manuelle Zuweisung der Konstruktoreigenschaft ist nicht sehr idiomatische Verwendung von JavaScript.

Question

Ich versuche, mich um den Kopf herum zu drehen, um Javascript auf OO anzuwenden ... und, wie viele andere auch, über die constructor in Unordnung zu geraten. Insbesondere die Signifikanz der constructor , da ich scheinbar keine Wirkung erzielen kann. Z.B:

function Foo(age) {
    this.age = age;
}

function Bar() {
    this.name = "baz"; 
}

Bar.prototype = new Foo(42); 
var b = new Bar;    

alert(b.constructor); // "Foo". That's OK because we inherit `Foo`'s prototype.
alert(b.name);        // "baz". Shows that Bar() was called as constructor.
alert(b.age);         // "42", inherited from `Foo`.

Im obigen Beispiel scheint das Objekt b den richtigen Konstruktor namens ( Bar ) zu haben - und erbt die age-Eigenschaft von Foo . Warum schlagen viele Leute das als notwendigen Schritt vor?

Bar.prototype.constructor = Bar;

Offensichtlich wurde beim Konstruieren von b der rechte Bar Konstruktor aufgerufen. Welchen Einfluss hat diese Prototyp-Eigenschaft also? Ich bin neugierig zu wissen, welchen praktischen Unterschied es tatsächlich macht, die Konstruktoreigenschaft korrekt zu setzen, da ich nicht feststellen kann, ob es Auswirkungen darauf hat, welcher Konstruktor tatsächlich aufgerufen wird, nachdem ein Objekt erstellt wurde.




Einer der Anwendungsfälle, in denen die prototype.constructor Eigenschaft die Neuzuweisung von prototype.constructor überleben soll, ist die Definition einer Methode für den prototype , die neue Instanzen desselben Typs wie die angegebene Instanz erzeugt. Beispiel:

function Car() { }
Car.prototype.orderOneLikeThis = function() {  // Clone producing function
    return new this.constructor();
}
Car.prototype.advertise = function () {
    console.log("I am a generic car.");
}

function BMW() { }
BMW.prototype = Object.create(Car.prototype);
BMW.prototype.constructor = BMW;              // Resetting the constructor property
BMW.prototype.advertise = function () {
    console.log("I am BMW with lots of uber features.");
}

var x5 = new BMW();

var myNewToy = x5.orderOneLikeThis();

myNewToy.advertise(); // => "I am BMW ..." if `BMW.prototype.constructor = BMW;` is not 
                      // commented; "I am a generic car." otherwise.