前陣子跟一個同事說:建立對象時,原型上只定義方法就行,屬性定義在構造函數裏面。他問了句:爲何?我竟然思索了半天,知識有時真的不用就會忘,經過寫做能加深印象,咱們來看下面的例子:javascript
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' ],很明顯,兩個不一樣的子類之間的數據相互混雜在一塊兒了。那咱們試試將屬性移到構造函數裏面:java
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' ],問題是否是就解決了?這種方法被稱做」借用構造函數「(有時也稱爲僞造對象或者經典繼承)。ui