JavaScript 繼承

繼承是JS中非常內(nèi)容,原因就是JS沒(méi)有地道的繼承方式,我們只能通過(guò)各種方式來(lái)模擬面向?qū)ο笾械睦^承。下面介紹幾種常見(jiàn)的繼承方式及其不足。

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

function Parent1 (){
    this.name = 'parent'
}

function Child1() {
    Parent1.call(this);
    this.type = 'child1';
}

缺點(diǎn):Parent1 原型鏈上的東西并不會(huì)繼承,這種方式,所以只實(shí)現(xiàn)了部分繼承,如果父類(lèi)的屬性都在構(gòu)造函數(shù)中,沒(méi)問(wèn)題,但是如果有一部分在原型鏈上,那么就繼承不了,為了解決這個(gè)不足我們就要使用原型鏈來(lái)進(jìn)行原型繼承。

原型繼承

function Parent2() {
this.name = 'Parent2';
this.res = [1, 2, 3]
}

function Child2 () {
this.type = 'Child2'
}

Child2.prototype = new Parent2()

var child2 = new Child2();
var child3 = new Child3();

child2.res.push(4);
console.log(child3.res) // 1,2,3,4

缺點(diǎn) : 這種方式缺點(diǎn)也很明顯,實(shí)例的兩個(gè)對(duì)象,如果一個(gè)對(duì)象改變r(jià)es的值,那么另一個(gè)對(duì)象 的res屬性也會(huì)被改變(這兩個(gè)對(duì)象共享一個(gè)原型),這違背了獨(dú)立性。

組合

function Parent3() {
    this.name = 'parent3';
    this.res = [1, 2, 3];
}

function Child3() {
    Parent3.call(this);
    this.type = 'child3';
}

Child3.prototype = Parent3.prototype;
var child = new Child3();

缺點(diǎn):此時(shí)child.constructor并不是Child3;而是Parent3,這是因?yàn)楫?dāng)我們想獲取child.constructor實(shí)際上是訪問(wèn)Child3.prototype.constructor(也就是說(shuō)constructor這個(gè)屬性是存在于原型上,并不是直接在child這個(gè)對(duì)象上),而Child3.prototype此時(shí)等于Parent3.prototype,所以最后constructor的屬性值為Parent3。

組合優(yōu)化

function Parent4() {
this.name = 'parent4';
this.res = [1, 2, 3];
}

function Child4() {
 Parent4.call(this);
 this.type = 'child4';
}

Child4.prototype = Object.create(Parent4.prototype);
// Child4.prototype = Parent4.prototype;
Child4.prototype.constructor = Child4;  

在這里我們加上這句Child4.prototype = Object.create(Parent4.prototype);的目的是為了隔離子類(lèi)原型和父類(lèi)原型,現(xiàn)在就是Child4.prototype.__proto__ === Parent4.prototype,如果我們不加,直接修正子類(lèi)的構(gòu)造函數(shù)(Child4.prototype.constructor = Child4;)那么也會(huì)把父類(lèi)的Parent4.prototype.constructor更改成Child4,因?yàn)榇藭r(shí)Child4.prototypeParent4.prototype指向同一地址。

注: 如果這里不支持Object.create,我們可以采用下面的plolly
function F(){} F.prototype = Parent4.prototype Child4.prototype = new F()

缺點(diǎn):貌似還沒(méi)有實(shí)現(xiàn)靜態(tài)屬性的繼承

實(shí)現(xiàn)靜態(tài)屬性的繼承

function Parent() {
  this.age = 20
}

Parent.sex = 'male';
Parent.habby = 'badminton';

function Child() {
  Parent.call(this);
  this.type = 'Child';

 if (Object.setPrototypeOf) {
   Object.setPrototypeOf(Child, Parent)
 } else if (Child.__proto__) {
   Child.__proto__ = Parent
 } else {
   for (var attr in Parent) {
     if (Parent.hasOwnProperty(attr) && !(attr in Child)) {
       Child[attr] = Parent[attr]
     }
   }
 }   
}

Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;

var child = new Child();
var parent = new Parent();
console.log(child)
for (var key in Child) {
  console.log(key)
}

console.log(child.constructor)
console.log(parent.constructor)
console.log(child instanceof Child)
console.log(child instanceof Parent)

看似完美了,但是還有一個(gè)問(wèn)題,就是如果后續(xù)父類(lèi)繼續(xù)添加一些靜態(tài)的方法,是不會(huì)自動(dòng)同步到子的靜態(tài)方法上面去的。

最后(歡迎大家關(guān)注我)

DJL簫氏個(gè)人博客
博客GitHub地址
簡(jiǎn)書(shū)
掘金

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 之前的JavaScript繼承一文中已經(jīng)介紹了繼承,但那篇只能算簡(jiǎn)介。本篇結(jié)合原型鏈詳細(xì)介紹一下JavaScrip...
    張歆琳閱讀 2,679評(píng)論 0 8
  • 我是誰(shuí),我來(lái)自哪,我是誰(shuí)的誰(shuí) 想必大家一定在學(xué)習(xí)或者開(kāi)發(fā)過(guò)程常常被JS獨(dú)有的原型繼承撥過(guò)不少腦弦吧,為何不迎問(wèn)題而...
    俗三瘋閱讀 386評(píng)論 0 2
  • 現(xiàn)在有一個(gè)"動(dòng)物"對(duì)象的構(gòu)造函數(shù),還有一個(gè)"貓"對(duì)象的構(gòu)造函數(shù)。 怎樣才能使"貓"繼承"動(dòng)物"呢? 一、 構(gòu)造函數(shù)...
    wavesnow閱讀 370評(píng)論 0 1
  • 例子 我們生成兩個(gè)構(gòu)造函數(shù),后面的例子都是讓‘’貓‘’繼承‘’動(dòng)物‘’的所有屬性和方法。 動(dòng)物(為了更好的理解各種...
    流光號(hào)船長(zhǎng)閱讀 370評(píng)論 0 1
  • 文/雪中萍 昨天,七節(jié)“生命樹(shù)”微學(xué)院家庭教育課結(jié)束,有點(diǎn)兒過(guò)去上學(xué)放假的感覺(jué)——輕松,看看所記筆記和作業(yè),很有...
    雪中萍閱讀 7,555評(píng)論 8 11

友情鏈接更多精彩內(nèi)容