不能我只是寫沒有這些行的代碼,這將是完全一樣的?
不,你在一般情況下確實需要它們兩個。是的,在某些特定情況下,您可以在沒有其中一個或兩個的情況下離開。
首先,請注意,該代碼在其中存在常見錯誤。這是不正確的:
Consultant.prototype = new Employee(); // INCORRECT
它應該是:
Consultant.prototype = Object.create(Employee.prototype);
new Employee
做兩個不同的東西:
它創建一個使用Employee.prototype
作爲其原型對象
它運行中的代碼10,他的工作就是通過設置屬性和這樣的this
初始化的Employee
實例,但我們不希望出現這種情況。第二部分呢。 Consultant.prototype
不是Employee
實例,它是一個對象,該對象將變得經由new Consultant
創建的對象的原型(這將是Employee
一個實例,並且還Consultant
)。 (這是JavaScript的構造函數和prototype
財產標準原型繼承離開。你可以做標準的原型繼承在JavaScript中,但是當你做什麼,你不使用構造函數中,prototype
財產,或new
)
Object.create
只是做了這兩個任務中的第一個:使用Employee.prototype
作爲原型創建一個對象。所以我們最終得到一個Consultant.prototype
上的對象,它使用Employee.prototype
作爲它的原型,但是沒有調用Employee
,並讓它運行其每個實例的初始化代碼。 (我們稍後會在第二行中標註X.)
但是爲什麼我們不想Employee
執行其每個實例的初始化?因爲Consultant.prototype
不是Employee
實例,所以將它初始化爲一個實例是沒有意義的。有一件事:如果Employee
需要使用參數來初始化它返回的對象呢?構建Consultant.prototype
時我們會通過什麼?我們沒有任何特定於實例的信息在此時傳遞它。
因此,相反,我們只是做#1以上(通過Object.create
),並留下#2(主叫Employee
),直到我們構造一個實例,通過(下文)調用從Consultant
Employee.call(this)
。
要將標線:
Employee.call(this);
這條線是必不可少給Employee
的機會做創建的實例的初始化。沒有它,Employee
還沒有機會完成它的工作:初始化Employee
部分的實例。例如,假設Employee
看起來是這樣的:
function Employee() {
this.paySchedule = "biweekly";
}
如果沒有Consultant
的Employee.call(this);
線,該屬性會從通過new Consultant
創建一個實例會丟失。
你的第二個標記行:
Consultant.prototype.constructor = Consultant;
我們需要這樣做,因爲Consultant.prototype
的constructor
屬性應該指向Consultant
,但如果我們不這樣做,它會指向Employee
。
它並沒有太多用處,因爲儘管constructor
在規範中被定義爲默認設置,但在規範中沒有用於使用它。在ES2015中改變了(又名「ES6」):現在,有時使用constructor
屬性(例如,在promise中)。
下面是一個例子,說明Employee
有參數的情況。我也切換到PayEmployee
到payEmployee
在與JavaScript中的壓倒性的慣例,唯一的構造函數最初皚皚保持:
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();
最後,我會如果我沒有指出ES2015的話,我們有class
的語法,如果需要的話可以在較老的環境下進行轉換:
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();
你問到Consultant.prottype = new Employee();
是否永遠是錯的。讓我們一版本使用new Employee
是什麼,以及消除你與X標誌着兩行代碼,並加入到員工的一個功能,它看起來像它應該工作,但最終導致了種種困惑:
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?!
的問題是,staff
陣列上Consultant.prototype
,不是每個實例,所以無論我們使用的情況下,我們總是訪問相同的陣列。
這就是爲什麼我們不使用用於初始化實例功能(例如,構造函數)來初始化一個構造函數的prototype
屬性的對象。
我應該注意到,在標準原型繼承中,實際創建一個實例成爲另一個實例的原型將是常見和正常的。但是JavaScript的構造函數和它們的屬性並不是標準的原型繼承,它們是基於類的OOP和原型OOP的混合。你可以在JavaScript中完成純原型的OOP(還有很多),但是當你這樣做時,你不使用構造函數,它們的prototype
屬性或new
。您使用工廠功能和Object.create
(通常)。
*目前*他們可能沒有任何區別。嘗試在基類'員工'上定義其他屬性和方法,但不是'顧問',我相信你會發現一些東西:) – Jokester