JS繼承方式總結(jié) (轉(zhuǎn))



借用構(gòu)造函數(shù)繼承

原型鏈?zhǔn)嚼^承(借用原型鏈實(shí)現(xiàn)繼承)

組合式繼承

組合式繼承優(yōu)化1

組合式繼承優(yōu)化2

ES6中繼承

JS面向?qū)ο笾R中升筏,繼承是比較難比較抽象的一塊內(nèi)容黍聂,而且實(shí)現(xiàn)繼承有很多種方法丸逸,每種方法又各有優(yōu)缺點(diǎn)超陆,更加的讓人奔潰谢肾,這需要對面向?qū)ο笾R中的對象、原型钦铺、原型鏈傀蓉、構(gòu)造函數(shù)等基礎(chǔ)知識掌握透徹,否則《JS高程》里第六章繼承也是看不明白的职抡,網(wǎng)上也有N多的文章葬燎,看了這么多對繼承依然不是很明白,所謂懂得不少道理但依然過不好這一生缚甩。

下面我結(jié)合自己的理解谱净,和參考了《JS高程》和網(wǎng)上文章,總結(jié)一下實(shí)現(xiàn)繼承的幾種方法及優(yōu)缺點(diǎn)擅威,這篇文章適合出去面試前速記壕探。

借用構(gòu)造函數(shù)繼承

function Parent0(){

this.name = "parent0";

this.colors = ["red","blue","yellow"];

}

function Child0(){

Parent0.call( this ); // 或apply

this.type = "child0";

}

第6行,在子類(Child0)中執(zhí)行父類(Parent0)的構(gòu)造函數(shù)郊丛,通過這種調(diào)用李请,把父類構(gòu)造函數(shù)的this指向?yàn)樽宇悓?shí)例化對象引用瞧筛,從而導(dǎo)致父類執(zhí)行的時候父類里面的屬性都會被掛載到子類的實(shí)例上去。

new Child0().name; // Parent0

new Child0().colors; // (3) ["red", "blue", "yellow"]

但是通過這種方式导盅,父類原型上的東西是沒法繼承的

Parent0.prototype.sex = "男";

Parent0.prototype.say = function() {

console.log(" Oh,My God! ");

}

new Child0().sex; // undefined

// Uncaught TypeError: (intermediate value).say is not a function

new Child0().say();

缺點(diǎn):Child1無法繼承Parent1的原型對象较幌,并沒有真正的實(shí)現(xiàn)繼承(部分繼承)

原型鏈?zhǔn)嚼^承(借用原型鏈實(shí)現(xiàn)繼承)

function Parent1(){

this.name = "parent1";

this.colors = ["red","blue","yellow"];

}

function Child1(){

this.name = "child1";

}

Child1.prototype = new Parent1();

這種方式能否解決借用構(gòu)造函數(shù)繼承的缺點(diǎn)呢?來看下面代碼白翻,我們依然為父類的原型添加sex屬性和say方法:

Parent1.prototype.sex = "男";

Parent1.prototype.say = function() {

console.log(" Oh,My God! ");

}

new Child1().sex; // ?男

new Child1().say(); // Oh,My God!

這種方式確實(shí)解決了上面借用構(gòu)造函數(shù)繼承方式的缺點(diǎn)乍炉。

但是,這種方式仍有缺點(diǎn)滤馍,我們來看如下代碼:

var s1 = new Child1();

s1.colors.push("black");

var s2 = new Child1();

s1.colors; // (4) ["red", "blue", "yellow", "balck"]

s2.colors; // (4) ["red", "blue", "yellow", "balck"]

我們實(shí)例化了兩個Child1岛琼,在實(shí)例s1中為父類的colors屬性push了一個顏色,但是s2也被跟著改變了巢株。造成這種現(xiàn)象的原因就是原型鏈上中的原型對象它倆是共用的槐瑞。

這不是我們想要的,s1和s2這個兩個對象應(yīng)該是隔離的阁苞,這是這種繼承方式的缺點(diǎn)困檩。

組合式繼承

這里所謂的組合是指組合借用構(gòu)造函數(shù)和原型鏈繼承兩種方式。

function Parent2(){

this.name = "parent2";

this.colors = ["red","blue","yellow"];

}

function Child2(){

Parent2.call(this);

this.type = "child2";

}

Child2.prototype = new Parent2()

注意第6猬错,9行窗看,這種方式結(jié)合了借用構(gòu)造函數(shù)繼承和原型鏈繼承的有點(diǎn),能否解決上述兩個實(shí)例對象沒有被隔離的問題呢倦炒?

var s1 = new Child2();

s1.colors.push("black");

var s2 = new Child2();

s1.colors; // (4) ["red", "blue", "yellow", "balck"]

s2.colors; // (3) ["red", "blue", "yellow"]

可以看到显沈,s2和s1兩個實(shí)例對象已經(jīng)被隔離了。

但這種方式仍有缺點(diǎn)逢唤。父類的構(gòu)造函數(shù)被執(zhí)行了兩次拉讯,第一次是Child2.prototype = new Parent2(),第二次是在實(shí)例化的時候鳖藕,這是沒有必要的魔慷。

組合式繼承優(yōu)化1

直接把父類的原型對象賦給子類的原型對象

function Parent3(){

this.name = "parent3";

this.colors = ["red","blue","yellow"];

}

Parent3.prototype.sex = "男";

Parent3.prototype.say = function(){console.log("Oh, My God!")}

function Child3(){

Parent3.call(this);

this.type = "child3";

}

Child3.prototype = Parent3.prototype;

var s1 = new Child3();

var s2 = new Child3();

console.log(s1, s2);

但是著恩,我們來看如下代碼:

console.log(s1instanceofChild3); // true

console.log(s1instanceofParent3); // true

可以看到院尔,我們無法區(qū)分實(shí)例對象s1到底是由Child3直接實(shí)例化的還是Parent3直接實(shí)例化的。用instanceof關(guān)鍵字來判斷是否是某個對象的實(shí)例就基本無效了喉誊。

我們還可以用.constructor來觀察對象是不是某個類的實(shí)例:

console.log(s1.constructor.name); // Parent3

從這里可以看到邀摆,s1的構(gòu)造函數(shù)居然是父類,而不是子類Child3伍茄,這顯然不是我們想要的栋盹。

組合式繼承優(yōu)化2

這是繼承的最完美方式

function Parent4(){

this.name = "parent4";

this.colors = ["red","blue","yellow"];

}

Parent4.prototype.sex = "男";

Parent4.prototype.say = function(){console.log("Oh, My God!")}

function Child4(){

Parent4.call(this);

this.type = "child4";

}

Child4.prototype = Object.create(Parent4.prototype)敷矫;

Child4.prototype.constructor = Child4;

Object.create是一種創(chuàng)建對象的方式例获,它會創(chuàng)建一個中間對象

var p = {name: "p"}

var obj = Object.create(p)

// Object.create({ name: "p" })

通過這種方式創(chuàng)建對象汉额,新創(chuàng)建的對象obj的原型就是p,同時obj也擁有了屬性name榨汤,這個新創(chuàng)建的中間對象的原型對象就是它的參數(shù)蠕搜。

這種方式解決了上面的所有問題,是繼承的最完美實(shí)現(xiàn)方式件余。

ES6中繼承

Class 可以通過extends關(guān)鍵字實(shí)現(xiàn)繼承讥脐,這比 ES5 的通過修改原型鏈實(shí)現(xiàn)繼承遭居,要清晰和方便很多啼器。

class Parent {

}

class Child1extendsParent {

constructor(x, y, colors) {

super(x, y); // 調(diào)用父類的constructor(x, y)

this.colors = colors;

}

toString() {

return this.colors + ' ' + super.toString(); // 調(diào)用父類的toString()

}

}

上面代碼中,constructor方法和toString方法之中俱萍,都出現(xiàn)了super關(guān)鍵字端壳,它在這里表示父類的構(gòu)造函數(shù),用來新建父類的this對象枪蘑。

子類必須在constructor方法中調(diào)用super方法损谦,否則新建實(shí)例時會報(bào)錯。如果子類沒有定義constructor方法岳颇,這個方法會被默認(rèn)添加照捡,不管有沒有顯式定義,任何一個子類都有constructor方法话侧。

ES5

的繼承栗精,實(shí)質(zhì)是先創(chuàng)造子類的實(shí)例對象this,然后再將父類的方法添加到this上面(Parent.apply(this))瞻鹏。ES6

的繼承機(jī)制完全不同悲立,實(shí)質(zhì)是先創(chuàng)造父類的實(shí)例對象this(所以必須先調(diào)用super方法),然后再用子類的構(gòu)造函數(shù)修改this新博。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末薪夕,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子赫悄,更是在濱河造成了極大的恐慌原献,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件埂淮,死亡現(xiàn)場離奇詭異姑隅,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)同诫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門粤策,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人误窖,你說我怎么就攤上這事叮盘≈确。” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵柔吼,是天一觀的道長毒费。 經(jīng)常有香客問我,道長愈魏,這世上最難降的妖魔是什么觅玻? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮培漏,結(jié)果婚禮上溪厘,老公的妹妹穿的比我還像新娘。我一直安慰自己牌柄,他們只是感情好畸悬,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著珊佣,像睡著了一般蹋宦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上咒锻,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天冷冗,我揣著相機(jī)與錄音,去河邊找鬼惑艇。 笑死蒿辙,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的敦捧。 我是一名探鬼主播须板,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼兢卵!你這毒婦竟也來了习瑰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤秽荤,失蹤者是張志新(化名)和其女友劉穎甜奄,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體窃款,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡课兄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了晨继。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片烟阐。...
    茶點(diǎn)故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蜒茄,到底是詐尸還是另有隱情唉擂,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布檀葛,位于F島的核電站玩祟,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏屿聋。R本人自食惡果不足惜空扎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望润讥。 院中可真熱鬧转锈,春花似錦、人聲如沸象对。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽勒魔。三九已至,卻和暖如春菇曲,著一層夾襖步出監(jiān)牢的瞬間冠绢,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工常潮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留弟胀,地道東北人。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓喊式,卻偏偏與公主長得像孵户,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子岔留,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容