js創(chuàng)建之初,正值java大行其道,面向?qū)ο缶幊檀猴L(fēng)正盛,js借鑒了java的對(duì)象機(jī)制,但僅是看起來(lái)像,也就是js的構(gòu)造函數(shù),如下:
function People(age) {
this.age = age;
this.getAge = function (){return this.age};
}
var p1 = new People(20);//People的實(shí)例1
var p2 = new People(40);//People的實(shí)例2
上面的代碼很像java了,通過(guò)new constructor()的方式,可以創(chuàng)建多個(gè)實(shí)例。
但上面代碼問(wèn)題是getAge方法會(huì)在每個(gè)People的實(shí)例中存在,如果實(shí)例多的話(huà),會(huì)浪費(fèi)很多空間,js采用了犧牲時(shí)間,獲取空間的方法,js引入了原型理念,將方法放入原型中:
function People(age) {
this.age = age
}
People.prototype.getAge = function () {return this.age};
本文就來(lái)總結(jié)下,如何使用構(gòu)造函數(shù)來(lái)實(shí)現(xiàn)繼承。
我們假設(shè)我們有一個(gè)父構(gòu)造函數(shù)People和子構(gòu)造函數(shù)Student,People有一個(gè)屬性age和一個(gè)方法getAge,Student有一個(gè)屬性num和getNum。
function People(age) {
this.age = age;
}
People.prototype.getAge = function (){return this.age;};
function Student(num) {
this.num = num;
}
Student.prototype.getNum = function () {return this.num;};
我們要實(shí)現(xiàn)是Student繼承People,這在js里可要費(fèi)一番力氣了。
我們可以利用js的原型機(jī)制,將子構(gòu)造函數(shù)的原型屬性設(shè)置為父構(gòu)造函數(shù)的實(shí)例,這是js中比較常用的方式:
function Student(num) {
this.num = num;
}
Student.prototype = new People();
Student.prototype.getNum = function () {return this.num;};
var stu1 = new Student('123');
這樣做其實(shí)基本實(shí)現(xiàn)了我們的需求,但如果深入思考上面的方式,其實(shí)有幾個(gè)缺點(diǎn):
哦?。?!
先來(lái)看看如何解決第一個(gè)問(wèn)題,我們可以巧用js的call方法,如果你還不知道這個(gè)方法,請(qǐng)移步這里。
function Student(age, num) {
People.call(this, age);
this.num = num;
}
我們?cè)谧訕?gòu)造函數(shù)內(nèi)部,借用父構(gòu)造函數(shù),這樣就巧妙地在子類(lèi)中繼承了父類(lèi)的實(shí)例化屬性。這其實(shí)類(lèi)似java的super關(guān)鍵字。
再來(lái)看看如何解決第二個(gè)問(wèn)題,解決這個(gè)問(wèn)題,其實(shí)我們可以將子構(gòu)造函數(shù)的原型更改為父構(gòu)造函數(shù)的原型,而不是父構(gòu)造函數(shù)的實(shí)例。
Student.prototype = People.prototype;
這樣就不會(huì)將父構(gòu)造函數(shù)的實(shí)例屬性擴(kuò)展到子構(gòu)造函數(shù)的原型上了。
但這樣做會(huì)導(dǎo)致另一個(gè)問(wèn)題,就是無(wú)法再在Student的原型上擴(kuò)展方法了,因?yàn)闀?huì)擴(kuò)展同時(shí)會(huì)擴(kuò)展到People的原型上。
為了解決上面引發(fā)的問(wèn)題,和第三個(gè)問(wèn)題。我們可以在子構(gòu)造函數(shù)和父構(gòu)造函數(shù)之間,加一層臨時(shí)構(gòu)造函數(shù)。
function F() {
}
F.prototype = People.prototype;
Student.prototype = new F();
這樣就可以Student的原型上擴(kuò)展子構(gòu)造函數(shù)的方法,同時(shí)不影響父構(gòu)造函數(shù)的原形了。
在修復(fù)一下constructor屬性就ok啦
Student.prorotype.constructor = Student;
我們將上面的幾種方法綜合起來(lái),代碼看起來(lái)就像下面這樣子:
//繼承函數(shù)
function inherit(C, P) {
var F = function (){};
F.prototype = P.prototype;
C.prototype = new F();//臨時(shí)構(gòu)造函數(shù)
C.prototype.constructor = C;//修復(fù)constructor
C.uper = P;//存儲(chǔ)超類(lèi)
}
function People(age) {
this.age = age;
}
People.prototype.getAge = function (){return this.age;};
function Student(age, num) {
Student.uber.call(this, age);
this.num = num;
}
inherit(Student, People);//繼承父構(gòu)造函數(shù)
Student.prototype.getNum = function () {return this.num;};
本文大部分內(nèi)容其實(shí)出自,《javascript模式》第五章 代碼的復(fù)用模式。記錄下來(lái)省的自己每次都要去翻書(shū)了,當(dāng)然主要還是寫(xiě)給MM看的。
更多建議: