總結(jié)JavaScript幾種繼承的方式及優(yōu)缺點(diǎn)

1. 原型繼承

原型繼承是比較常見一種繼承方式

function Parent() {
  this.name = 'parent'
  this.action = function () {
    console.log(this.name)
    return this.name
  },
  this.arr = [1,2]
}

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

function Child() {
  this.name = 'child'
}
// 實例化父函數(shù)抡蛙,鏈接到自己的原型鏈上
Child.prototype = new Parent
const child1 = new Child
console.log(child1)

child.png

從上圖中可以看到, 原型繼承的特點(diǎn):把父類的公有(prototype)+私有屬性都繼承到了子類的原型上(公有屬性 prototype)

注意:原型繼承的缺點(diǎn)

  const child2 = new Child
  console.log(child1)
  child2.arr.push(3)

如果有一個子類 child2 調(diào)用 父類的 arr 屬性并添加了內(nèi)容
此時來看 child1 和 child2

child1.png

從上面的結(jié)果中發(fā)現(xiàn)轮锥,child2 修改了父類的屬性幽告,child1 的父類屬性也被修改了。這也很好理解鹊奖,因為它倆都繼承與同一個 parent。它們的內(nèi)存空間是共享的。
所以:原型的缺點(diǎn):子類會共享父類的的內(nèi)存空間

構(gòu)造函數(shù)繼承(call或apply)

function Parent() {
  this.name = 'parent'
  this.action = function () {
    console.log(this.name)
    return this.name
  },
  this.arr = [1,2]
}

Parent.prototype.getName = function () {
  console.log(this.name)
  return this.name
}
function Child () {
  // 還有這里注意液走,如果子類的屬性名和父類的一樣,要看它的循序贾陷,誰在下面用誰的聲明
  this.name = 'Child'
  // Parent.call(this)
  Parent.apply(this)
}
const child1 = new Child
const child2 = new Child
child2.arr.push(3)
console.log('child1 --->', child1)
console.log('child2 --->', child2)

call.png

使用這種解決了數(shù)據(jù)共享的問題
但是: 只能繼承父類的實例屬性和方法缘眶,不能繼承原型屬性或者方法。

組合繼承 (call + prototype)

function Parent() {
  this.name = 'parent'
  this.action = function () {
    console.log(this.name)
    return this.name
  },
  this.arr = [1,2]
}
Parent.prototype.getName = function () {
  console.log(this.name)
  return this.name
}

function Child() {
  this.name = 'child'
  Parent.call(this)
}
Child.prototype = new Parent
Child.prototype.constructor = Child
const child1 = new Child
console.log(child1)

image.png

優(yōu)點(diǎn):解決了 原型繼承和構(gòu)造函數(shù)繼承的缺點(diǎn)髓废。
但是這種方式也有缺陷:從上圖中可以看出巷懈,子類原型上多了一份父類的實例屬性。因為父類的構(gòu)造函數(shù)被調(diào)用了兩次慌洪,生成了兩份顶燕,子類實例上的屏蔽了原型上的,造成了內(nèi)存浪費(fèi)

寄生式繼承 (Object.create)

就是使用原型繼承獲取一份淺拷貝對象冈爹。然后利用這個淺拷貝對象在進(jìn)行增強(qiáng)涌攻。
缺點(diǎn)和原型繼承一樣,但對于普通對象的繼承來說频伤,可以在父類的基礎(chǔ)上添加更多的方法

let Parent1 = {
  arr: ['a', 'b'],
  name: 'Parent1',
  getName: function() {
    return this.name
  }
}
function Child(parent) {
  let copy = Object.create(parent)
  console.log(copy)
  copy.getArray = function () {
    return this.arr
  }
  return copy
}

let Child1 = Child(Parent1)
console.log(Child(Parent1))
console.log('child1 -->', Child1.getArray()) // ['a', 'b']
console.log('child1 -->', Child1.getName()) // Parent1
  • 缺點(diǎn) 不能實例化恳谎,也沒有用到原型。

寄生組合式繼承

function Parent() {
  this.name = 'parent'
  this.action = function () {
    return this.name
  },
  this.arr = [1,2]
}

Parent.prototype.getName = function () {
  return this.name
}

function Child() {
  Parent.call(this)
}
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child

const child1 = new Child
const child2 = new Child
console.log(child1)
  • 解決了上面幾種幾種的缺陷剂买,也較好的實現(xiàn)了繼承的結(jié)果即 父類私有屬性放放子類私有中惠爽,原型上的屬性和方法放到子類原型上

注意:上面寫的繼承中癌蓖,為什么要手動修改 constructor 的指向
因為:在 JS 的規(guī)定中,xxx.prototype.constructor 的指向是當(dāng)前函數(shù)(類)本身婚肆。也就是指向自己租副,我們上面用到的寄生繼承、組合繼承等较性,如果不修改 constructor 的指向用僧,它會指向 Parent 這個類, 如下:

// Child.prototype.constructor = Child
 console.log('constructor -->', Child.prototype.constructor === Parent) // true 

去掉手動指向,Child 的 constructor 就指向了 Parent赞咙,所以違背了 JS 的標(biāo)準(zhǔn)規(guī)范责循。

ES6 extends 關(guān)鍵字

在 ES6 中,直接使用 extends 關(guān)鍵字可以很容易的實現(xiàn) JavaScript 繼承攀操,并且 babel 編輯之后院仿,它采用的也是 寄生組合繼承的方式,這種方式是較優(yōu)的解決繼承的方式速和。

class Parent2 {
  constructor(name) {
    this.name = name
  }
  getName = function (){
    return this.name
  }
}
class Child2 extends Parent2 {
  constructor(name, age) {
    super(name)
    this.age = age
  }
}
const child3 = new Child2('parent', 22)
const child4 = new Child2('parent1', 25)
console.log(child3.getName())
console.log(child3)
console.log(child4)
extends.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末歹垫,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子颠放,更是在濱河造成了極大的恐慌排惨,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碰凶,死亡現(xiàn)場離奇詭異暮芭,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)欲低,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門辕宏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人伸头,你說我怎么就攤上這事匾效。” “怎么了恤磷?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵面哼,是天一觀的道長。 經(jīng)常有香客問我扫步,道長魔策,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任河胎,我火速辦了婚禮闯袒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己政敢,他們只是感情好其徙,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著喷户,像睡著了一般唾那。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上褪尝,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天闹获,我揣著相機(jī)與錄音,去河邊找鬼河哑。 笑死避诽,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的璃谨。 我是一名探鬼主播沙庐,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼睬罗!你這毒婦竟也來了轨功?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤容达,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后垂券,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體花盐,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年菇爪,在試婚紗的時候發(fā)現(xiàn)自己被綠了算芯。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡凳宙,死狀恐怖熙揍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情氏涩,我是刑警寧澤届囚,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站是尖,受9級特大地震影響意系,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜饺汹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一蛔添、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦迎瞧、人聲如沸夸溶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽缝裁。三九已至,卻和暖如春咏尝,著一層夾襖步出監(jiān)牢的瞬間压语,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工编检, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留胎食,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓允懂,卻偏偏與公主長得像厕怜,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蕾总,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345

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