JS對象繼承時,對引用屬性的處理

前陣子跟一個同事說:建立對象時,原型上只定義方法就行,屬性定義在構造函數裏面。他問了句:爲何?我竟然思索了半天,知識有時真的不用就會忘,經過寫做能加深印象,咱們來看下面的例子: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

溫故而知新,有時東西工做時寫成了習慣,就會忘記原理。

相關文章
相關標籤/搜索