前陣子跟一個同事說:建立物件時,原型上只定義方法就行,屬性定義在建構函式裡面。他問了句:為什麼?我居然思索了半天,知識有時真的不用就會忘,通過寫作能加深印象,我們來看下面的例子:
function SuperCompany() {}
SuperCompany.prototype.staffs = [];
SuperCompany.prototype.addStaff = function(name) {
this.staffs.push(name);
}
SuperCompany.prototype.printStaff = function() {
console.log(`staffs:`, this.staffs);
}
function Company() {}
Company.prototype = new SuperCompany();
let companyA = new Company();
companyA.addStaff(`peter`);
let companyB = new Company();
companyB.addStaff(`nina`);
companyA.printStaff();
companyB.printStaff();
複製程式碼
上述程式碼,輸出都是一樣的:[ `peter`, `nina` ],很明顯,兩個不同的子類之間的資料相互混雜在一起了。那我們試試將屬性移到建構函式裡面:
function SuperCompany() {
this.staffs = [];
}
SuperCompany.prototype.addStaff = function(name) {
this.staffs.push(name);
}
SuperCompany.prototype.printStaff = function() {
console.log(`staffs:`, this.staffs);
}
function Company() {}
Company.prototype = new SuperCompany();
let companyA = new Company();
companyA.addStaff(`peter`);
let companyB = new Company();
companyB.addStaff(`nina`);
companyA.printStaff();
companyB.printStaff();
複製程式碼
執行發現,結果並沒有變化,兩個不同的子類雖然複製了自己的staffs,但staffs是個引用型別,他們只複製了引用地址而已,指向的具體資料還是同一份,那麼怎麼解決呢?做下變通:
function SuperCompany() {
this.staffs = [];
}
SuperCompany.prototype.addStaff = function(name) {
this.staffs.push(name);
}
SuperCompany.prototype.printStaff = function() {
console.log(`staffs:`, this.staffs);
}
function Company() {
SuperCompany.call(this);
}
Company.prototype = new SuperCompany();
let companyA = new Company();
companyA.addStaff(`peter`);
let companyB = new Company();
companyB.addStaff(`nina`);
companyA.printStaff();
companyB.printStaff();
複製程式碼
再看下輸出,[ `peter` ]、[ `nina` ],問題是不是就解決了?這種方法被稱作”借用建構函式“(有時也稱為偽造物件或者經典繼承)。