Könnte ich nicht schreiben Sie einfach den Code ohne diese Linien und es würde genau das gleiche?
Nein, Sie brauchen beide im allgemeinen Fall. Ja, in bestimmten Fällen können Sie ohne eines oder beide davonkommen.
Zunächst einmal, beachten Sie, dass dieser Code einen allgemeinen Fehler enthält. Das ist falsch:
Consultant.prototype = new Employee(); // INCORRECT
Es sollte sein:
Consultant.prototype = Object.create(Employee.prototype);
new Employee
hat zwei verschiedene Dinge:
Es schafft ein Objekt, das Employee.prototype
als Prototyp verwendet
Es führt den Code in Employee
, deren Aufgabe es ist, eine Instanz von Employee
durch die Einrichtung von Eigenschaften und solche auf this
Aber wir wollen nicht, dass die zweiten Teil noch zu initialisieren. Consultant.prototype
ist kein Employee
Instanz, es ist ein Objekt, das der Prototyp eines Objekts über new Consultant
erstellt werden wird (die eine Instanz von Employee
sein wird und auch von Consultant
). (Dies ist, wo JavaScript Konstruktor Funktionen und prototype
Eigenschaft von Standard prototypische Vererbung abweichen. Sie können in JavaScript Standard prototypische Vererbung tun, aber wenn Sie tun, Sie nicht verwenden Konstruktorfunktionen, das prototype
Eigentum oder new
.)
Object.create
macht nur die erste dieser beiden Aufgaben: Erzeugt ein Objekt mit Employee.prototype
als seinen Prototyp.Also haben wir am Ende ein Objekt auf Consultant.prototype
, das Employee.prototype
als seinen Prototyp verwendet, aber ohne, das Employee
aufruft und es seinen pro-Instanzinitialisierungscode ausführen lässt. (Wir machen das später, in der zweiten Zeile, die Sie mit einem X markiert haben.)
Aber warum wollen wir nicht Employee
seine pro-Instanz-Initialisierung tun? Da Consultant.prototype
wiederum keine Employee
Instanz ist, macht es keinen Sinn, sie als eine zu initialisieren. Zum einen: Was ist, wenn Employee
Parameter benötigt, um das von ihm zurückgegebene Objekt zu initialisieren? Was würden wir bei der Konstruktion von Consultant.prototype
passieren? Wir haben keine instanzspezifischen Informationen, um sie zu diesem Zeitpunkt zu übergeben.
Also statt, wir tun # 1 nur oben (über Object.create
), und lassen Sie # 2 (Aufruf Employee
), bis wir eine Instanz sind die Konstruktion, durch Employee.call(this)
von Consultant
(mehr unten) aufrufen.
Um die markierten Linien:
Employee.call(this);
Diese Linie ist wichtig Employee
seine Chance zu geben, seine Initialisierung der Instanz zu tun geschaffen. Ohne es Employee
hatte keine Chance, seine Arbeit zu tun: Initialisieren Sie die Employee
Teile der Instanz. Zum Beispiel: Angenommen Employee
wie folgt aussieht:
function Employee() {
this.paySchedule = "biweekly";
}
Ohne die Employee.call(this);
Linie in Consultant
, würde diese Eigenschaft von einer Instanz über new Consultant
erstellt fehlen.
Ihre zweite markierte Zeile:
Consultant.prototype.constructor = Consultant;
Wir müssen dies tun, weil Consultant.prototype
‚s constructor
Eigenschaft Consultant
zeigen sollte, aber wenn wir dies nicht tun, wird es zu Employee
zeigen.
Es war nicht wichtig zu viel, weil obwohl constructor
in der Spezifikation definiert wurde auf diese Weise standardmäßig eingerichtet, nichts in der Spezifikation verwendet, um es zu verwenden. Das änderte sich in ES2015 (aka "ES6"): Jetzt wird die constructor
Eigenschaft manchmal verwendet (zum Beispiel in Versprechungen).
Hier ist ein Beispiel, die Situation darstellt, in dem Employee
Parameter.Ich habe auch PayEmployee
-payEmployee
geschaltet mit der überwältigenden Konvention in JavaScript sein zu halten, die nur Konstruktorfunktionen zunächst bedeckten:
function Employee(name, title) {
this.name = name;
this.title = title;
}
Employee.prototype.payEmployee = function() {
console.log("Time to pay " + this.name + " (" + this.title + ")");
};
function Consultant(name) {
Employee.call(this, name, "Consultant");
}
Consultant.prototype = Object.create(Employee.prototype);
Consultant.prototype.constructor = Consultant;
Consultant.prototype.payEmployee = function() {
console.log("Time to pay " + this.name + " (" + this.title + ") -- remember, you're paying the gross, consultants handle their own tax.");
};
var e = new Employee("Joe Bloggs", "Engineer");
e.payEmployee();
var c = new Consultant("John Smith");
c.payEmployee();
Und schließlich wäre ich remiss, wenn ich nicht darauf hingewiesen habe, dass ab ES2015, haben wir class
Syntax dafür, die bei Bedarf für ältere Umgebungen transpiliert werden kann:
class Employee {
constructor(name, title) {
this.name = name;
this.title = title;
}
payEmployee() {
console.log("Time to pay " + this.name + " (" + this.title + ")");
}
}
class Consultant extends Employee {
constructor(name) {
super(name, "Consultant");
}
payEmployee() {
console.log("Time to pay " + this.name + " (" + this.title + ") -- remember, you're paying the gross, consultants handle their own tax.");
}
}
const e = new Employee("Joe Bloggs", "Engineer");
e.payEmployee();
const c = new Consultant("John Smith");
c.payEmployee();
Sie werden gefragt, ob Consultant.prottype = new Employee();
ist immer falsch. Lassen Sie sich eine Version des Codes nimmt mit new Employee
für die, und das Entfernen der zwei Linien, die Sie mit X markiert, und fügen Sie eine Funktion, um Mitarbeiter, die wie es scheint, sollte zu funktionieren, aber endet für alle Arten von Verwirrung bis führende:
function Employee() {
this.staff = [];
}
Employee.prototype.payEmployee = function() {
console.log("Paying employee");
};
function Consultant(name) {
}
Consultant.prototype = new Employee();
Consultant.prototype.payEmployee = function() {
console.log("Time to pay " + this.name + " (" + this.title + ") -- remember, you're paying the gross, consultants handle their own tax.");
};
var jill1 = new Employee();
jill1.staff.push("Bob");
jill1.staff.push("Jane");
var john1 = new Employee();
john1.staff.push("Russell");
john1.staff.push("Mohammed");
console.log("Jill's staff (1): " + jill1.staff.join(", "));
console.log("John's staff (1): " + john1.staff.join(", "));
// so far so good, but what if we use Consultant instead?
var jill2 = new Consultant();
jill2.staff.push("Bob");
jill2.staff.push("Jane");
var john2 = new Consultant();
john2.staff.push("Russell");
john2.staff.push("Mohammed");
console.log("Jill's staff (2): " + jill2.staff.join(", "));
console.log("John's staff (2): " + john2.staff.join(", "));
// ??? how is it they both have all four staff?!
das Problem ist, dass die staff
Array auf Consultant.prototype
ist, nicht jede Instanz, und so unabhängig davon, welche Instanz die wir verwenden, sind wir immer das gleiche Array zugreifen.
Deshalb haben wir Funktionen nicht Instanzen initialisieren verwenden soll (zum Beispiel Konstruktorfunktionen) prototype
Eigenschaft des Objekts für eine Konstruktorfunktion der initialisieren.
Ich sollte beachten, dass es bei der standardmäßigen prototypischen Vererbung üblich und normal wäre, eine Instanz tatsächlich als Prototyp einer anderen Instanz zu erstellen. Aber die Konstruktorfunktionen von JavaScript und ihre -Eigenschaft sind keine standardmäßige prototypische Vererbung, sie sind eine Mischung aus klassenbasierter OOP und prototypischer OOP. Sie können reine prototypische OOP in JavaScript ausführen (und viele tun dies), aber wenn Sie dies tun, verwenden Sie keine Konstruktorfunktionen, ihre prototype
-Eigenschaft oder new
. Sie verwenden Fabrikfunktionen und Object.create
(normalerweise).
* zur Zeit * können sie keinen Unterschied anzeigen. Versuchen Sie, andere Eigenschaften und Methoden für die Basisklasse 'Employee' zu definieren, aber nicht' Consultant'. Ich glaube, Sie werden etwas finden. – Jokester