JavaScript 原型與原型鏈以及繼承方式

原型

ECMAScript 中描述了原型鏈的概念,并將原型鏈作為實(shí)現(xiàn)繼承的主要方法奇适。其基本思想是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法。簡單回顧一下構(gòu)造函數(shù)进鸠、原型和實(shí)例的關(guān)系:每個構(gòu)造函數(shù)都有一個原型對象媳握,原型對象都包含一個指向構(gòu)造函數(shù)的指針碱屁,而實(shí)例都包含一個指向原型對象的內(nèi)部指針。那么蛾找,假如我們讓原型對象等于另一個類型的實(shí)例娩脾,結(jié)果會怎么樣呢?顯然打毛,此時的原型對象將包含一個指向另一個原型的指針柿赊,相應(yīng)地,另一個原型中也包含著一個指向另一個構(gòu)造函數(shù)的指針隘冲。假如另一個原型又是另一個類型的實(shí)例闹瞧,那么上述關(guān)系依然成立,如此層層遞進(jìn)展辞,就構(gòu)成了實(shí)例與原型的鏈條奥邮。這就是所謂原型鏈的基本概念

繼承

繼承是OO 語言中的一個最為人津津樂道的概念。許多OO 語言都支持兩種繼承方式:接口繼承和
實(shí)現(xiàn)繼承罗珍。接口繼承只繼承方法簽名洽腺,而實(shí)現(xiàn)繼承則繼承實(shí)際的方法。如前所述覆旱,由于函數(shù)沒有簽名蘸朋,
在ECMAScript 中無法實(shí)現(xiàn)接口繼承。ECMAScript 只支持實(shí)現(xiàn)繼承扣唱,而且其實(shí)現(xiàn)繼承主要是依靠原型鏈
來實(shí)現(xiàn)的

原型與原型鏈

  1. prototype :每個函數(shù)都會有這個屬性藕坯,這里強(qiáng)調(diào),是函數(shù)噪沙,普通對象是沒有這個屬性的(這里為什么說普通對象呢炼彪,因?yàn)镴S里面,一切皆為對象正歼,所以這里的普通對象不包括函數(shù)對象)辐马。它是構(gòu)造函數(shù)的原型對象;
  2. proto :每個對象都有這個屬性,局义,這里強(qiáng)調(diào)喜爷,是對象,同樣萄唇,因?yàn)楹瘮?shù)也是對象檩帐,所以函數(shù)也有這個屬性。它指向構(gòu)造函數(shù)的原型對象穷绵;
  3. constructor :這是原型對象上的一個指向構(gòu)造函數(shù)的屬性轿塔。
function Pig(name: string, age: number){
  this.name = name
  this.age = age
}

// 創(chuàng)建Pig實(shí)例
const Pepig = new Pig('Pepig', 18)

// 在實(shí)例化的時候,prototype上的屬性會作為原型對象賦值給實(shí)例, 也就是Pepig原型
Pepig.__proto__ === Pig.prototype    // true

// Pig是一個函數(shù)對象, 它是Function對象的一個實(shí)例 Funtcion的原型對象又指向Object對象
Pig.__proto__ === Function.prototype  // true

Function.prototype.__proto__ === Object.prototype // true

Object.prototype.__proto__ === null // true

// 原型對象上的constructor指向構(gòu)造函數(shù)本身
Pig.prototype.constructor = Pig

繼承的方式

1.原型鏈繼承

function P(name: string){
  this.name = name
}

P.prototype.sayName = function(){
  console.log('P', this.name)
}

function C(name: string){
  this.name = name
}

C.prototype = new P('P')
C.prototype.constructor = C

C.prototype.sayName = function(){
  console.log('C', this.name)
}

const child = new C('C')
child.sayName() // 'C' C

缺點(diǎn)
  1. 子類型無法給超類型傳遞參數(shù),在面向?qū)ο蟮睦^承中勾缭,我們總希望通過 var child = new Child('son', 'father'); 讓子類去調(diào)用父類的構(gòu)造器來完成繼承揍障。而不是通過像這樣 new Parent('father') 去調(diào)用父類。
  2. 引用類型值的原型屬性會被所有實(shí)例共享

2.借用構(gòu)造函數(shù)(經(jīng)典繼承)

function P(age: number){
  this.names = ['alex', 'jet']
  this.age = age
}

function C(age: number){
  P.call(this, age)
}

const child = new C()
child.names.push('mark')  
child.names         // alex jet mark

const child1 = new C()
child1.names        // alex jet

const child = new C('15')
child.age           // 15

const child = new C('18')
child.age           // 18

優(yōu)點(diǎn)
  1. 避免了引用類型的屬性被所有實(shí)例共享
  2. 可以在 Child 中向 Parent 傳參
缺點(diǎn)
  1. 方法都在構(gòu)造函數(shù)中定義俩由,因此函數(shù)復(fù)用就無從談起了毒嫡。而且,在超類型的原型中定義的方法幻梯,對子類型而言也是不可見的兜畸。

3.組合繼承

function P(name: string){
  this.name = name
  this.colors = ['yellow', 'blue']
}

P.prototype.getName = function(){
  console.log(this.name)
}

function C(name: string, age: number){
  P.call(this, name)
  this.age = age
}

C.prototype = new P()

const child = new C('jet', 18)
child.colors.push('black')  // yellow blue black
child.name                  // jet
child.age                   //  18

const child1 new C('jack', 20)
child1.colors               // yellow blue
child1.name                 // jack
child1.age                  // 20    
優(yōu)點(diǎn)
  1. 融合原型鏈繼承和構(gòu)造函數(shù)的優(yōu)點(diǎn),是 JavaScript 中最常用的繼承模式碘梢。
  2. 都會調(diào)用兩次超類型構(gòu)造函數(shù)

4.原型式繼承

function object(o: Object){ 
  function F(){}
  F.prototype = o
  return new F() 
}

var person = { 
  name: "Nicholas", 
  friends: ["Shelby", "Court", "Van"] 
}
 
var anotherPerson = object(person)
anotherPerson.name = "Greg"
anotherPerson.friends.push("Rob")
 
var yetAnotherPerson = object(person)
yetAnotherPerson.name = "Linda"
yetAnotherPerson.friends.push("Barbie")
 
alert(person.friends)   //"Shelby,Court,Van,Rob,Barbie" 
特點(diǎn)
  1. 包含引用類型值的屬性始終都會共享相應(yīng)的值咬摇,就像使用原型模式一樣

5.寄生式繼承

思想: 寄生式繼承的思路與寄生構(gòu)造函數(shù)和工廠模式類似,即創(chuàng)建一個僅用于封裝繼承過程的函數(shù)煞躬,該
函數(shù)在內(nèi)部以某種方式來增強(qiáng)對象肛鹏,最后再像真地是它做了所有工作一樣返回對象

function createAnother(original){ 
  var clone = object(original)   //通過調(diào)用函數(shù)創(chuàng)建一個新對象 
  clone.sayHi = function(){      //以某種方式來增強(qiáng)這個對象 
    alert("hi") 
  } 
  return clone                   //返回這個對象 
}
缺點(diǎn)
  1. 使用寄生式繼承來為對象添加函數(shù),會由于不能做到函數(shù)復(fù)用而降低效率

6.寄生組合式繼承

function inheritPrototype(subType, superType){ 
  var prototype = object(superType.prototype);     //創(chuàng)建對象 
  prototype.constructor = subType;                 //增強(qiáng)對象 
  subType.prototype = prototype;                   //指定對象 
}
優(yōu)點(diǎn)

1.只調(diào)用了一次 SuperType 構(gòu)造函數(shù)恩沛,并且因此避免了在 SubType.
prototype 上面創(chuàng)建不必要的在扰、多余的屬性。與此同時雷客,原型鏈還能保持不變芒珠;因此,還能夠正常使用
instanceof 和 isPrototypeOf()

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末搅裙,一起剝皮案震驚了整個濱河市皱卓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌部逮,老刑警劉巖好爬,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異甥啄,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)炬搭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進(jìn)店門蜈漓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人宫盔,你說我怎么就攤上這事融虽。” “怎么了灼芭?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵有额,是天一觀的道長。 經(jīng)常有香客問我,道長巍佑,這世上最難降的妖魔是什么茴迁? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮萤衰,結(jié)果婚禮上堕义,老公的妹妹穿的比我還像新娘。我一直安慰自己脆栋,他們只是感情好倦卖,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著椿争,像睡著了一般怕膛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上秦踪,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天褐捻,我揣著相機(jī)與錄音,去河邊找鬼洋侨。 笑死舍扰,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的希坚。 我是一名探鬼主播边苹,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼裁僧!你這毒婦竟也來了个束?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤聊疲,失蹤者是張志新(化名)和其女友劉穎茬底,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體获洲,經(jīng)...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡阱表,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了贡珊。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片最爬。...
    茶點(diǎn)故事閱讀 40,912評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖门岔,靈堂內(nèi)的尸體忽然破棺而出爱致,到底是詐尸還是另有隱情,我是刑警寧澤寒随,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布糠悯,位于F島的核電站帮坚,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏互艾。R本人自食惡果不足惜试和,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望忘朝。 院中可真熱鬧灰署,春花似錦、人聲如沸局嘁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽悦昵。三九已至肴茄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間但指,已是汗流浹背寡痰。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留棋凳,地道東北人拦坠。 一個月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像剩岳,于是被迫代替她去往敵國和親贞滨。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,922評論 2 361