Class的繼承

1肯适、簡介
Class可以通過extends關(guān)鍵字實(shí)現(xiàn)繼承变秦,這比ES5的通過修改原型鏈實(shí)現(xiàn)繼承,要清晰和方便很多框舔。

class Point {
}
class ColorPoint extends Point {
}

上面代碼定義了一個ColorPoint類蹦玫,該類通過extends關(guān)鍵字,繼承了Point類的所有屬性和方法刘绣。但是由于沒有部署任何代碼樱溉,所以這兩個類完全一樣,等于復(fù)制了一個Point類纬凤。下面福贞,我們在ColorPoint內(nèi)部加上代碼。

class ColorPoint extends Point {
   constructor(x, y, color) {
      super(x,y)  //  調(diào)用父類的constructor(x,y)
      this.color = color;
   }
  toString() {
    return this.color + ' ' + super.toString()  //調(diào)用父類的toString()
  }
}

上面代碼中停士,constructor方法和toString方法之中挖帘,都出現(xiàn)了super關(guān)鍵字,它在這里表示父類的構(gòu)造函數(shù)恋技,用來新建父類的this對象拇舀。

子類必須在constructor方法中調(diào)用super方法,否則新建實(shí)例時(shí)會報(bào)錯蜻底。這是因?yàn)樽宇愖约旱膖his對象骄崩,必須先通過父類的構(gòu)造函數(shù)完成塑造,得到與父類同樣的實(shí)例屬性和方法,然后再對其進(jìn)行加工要拂,加上子類自己的實(shí)例屬性和方法抠璃。如果不調(diào)用super方法,子類就得不到this對象脱惰。

 class Point { /*......*/ }
 class ColorPoint extends Point {
    constructor() {
    }
 }
 let cp = new ColorPoint()

上面代碼中鸡典,ColorPoint繼承了父類Point,但是它的構(gòu)造函數(shù)沒有調(diào)用super方法枪芒,導(dǎo)致新建實(shí)例時(shí)報(bào)錯。

ES5的繼承谁尸,實(shí)質(zhì)是先創(chuàng)造子類的實(shí)例對象this舅踪,然后再將父類的方法添加到this上面(Parent.apply(this))。ES6的繼承機(jī)制完全不同良蛮,實(shí)質(zhì)是先將父類實(shí)例對象的屬性和方法抽碌,加到this上面(所以必須調(diào)用super方法),然后再用子類的構(gòu)造函數(shù)修改this决瞳。

如果子類沒有定義constructor方法货徙,這個方法會被默認(rèn)添加,代碼如下皮胡。也就是說痴颊,不管有沒有顯示定義,任何一個子類都有constructor方法屡贺。

 class ColorPoint extends Point {
 }
 //等同于
 class ColorPoint extends Point {
    constructor(...args) {
       super(...args)
    }
 }

另一個需要注意的地方是蠢棱,在子類的構(gòu)造函數(shù)中,只有調(diào)用super之后甩栈,才可以使用this關(guān)鍵字泻仙,否則會報(bào)錯。這是因?yàn)樽宇悓?shí)例的構(gòu)造量没,基于父類實(shí)例玉转,只有super方法才能調(diào)用父類實(shí)例。

2殴蹄、Object.getPrototypeOf()
Object.getPrototypeOf方法可以用來從子類上獲取父類究抓。

Object.getPrototypeOf(ColorPoint) === Point
// true

3、super關(guān)鍵字
super這個關(guān)鍵字袭灯,既可以當(dāng)作函數(shù)使用漩蟆,也可以當(dāng)作對象使用。在這種情況下妓蛮,它的用法完全不同怠李。

第一種情況,super作為函數(shù)調(diào)用時(shí),代表父類的構(gòu)造函數(shù)捺癞。ES6要求夷蚊,子類的構(gòu)造函數(shù)必須執(zhí)行一次super函數(shù)。

class A  { }
class B extends A {
    constructor() {
       super()
    }
}

注意髓介,super雖然代表了父類A的構(gòu)造函數(shù)惕鼓,但是返回的是子類B的實(shí)例,即super內(nèi)部this指的是B的實(shí)例唐础,因此super()在這里相當(dāng)于A.prototype.constructor.call(this)箱歧。

class A {
    constructor() {
      console.log(new.target.name)
    }
}
class B extends A {
    constructor() {
      super();
    }
}
new A ()  // A
new B ()  // B

上面代碼中,new.target指向當(dāng)前正在執(zhí)行的函數(shù)一膨⊙叫希可以看到,在super()執(zhí)行時(shí)豹绪,它指向的是子類B的構(gòu)造函數(shù)价淌,而不是父類A的構(gòu)造函數(shù),也就是說瞒津,super()內(nèi)部的this指向的是B蝉衣。

作為函數(shù)時(shí),super()只能用在子類的構(gòu)造函數(shù)之中巷蚪,用在其他地方就會報(bào)錯病毡。

class A { }
class B extends A {
   m() {
     super()  // 報(bào)錯
    }
 }

第二種情況,super作為對象時(shí)屁柏,在普通方法中剪验,指向父類的原型對象;靜態(tài)方法中前联,指向父類功戚。

class A {
    p () {
       return 2
    }
}
class B extends A {
    constructor() {
       super()
       console.log(super.p())  // 2
    }
}
let b = new B();

上面代碼中,子類B當(dāng)中的super.p()似嗤,就是將super當(dāng)作一個對象使用啸臀。這時(shí),super在普通方法之中烁落,指向A.prototype乘粒,所以super.p()就相當(dāng)于A.prototype.p()。

注意伤塌,由于super指向父類的原型對象灯萍,所以定義在父類實(shí)例上的方法或?qū)傩裕菬o法通過super調(diào)用的每聪。

class A {
   constructor() {
     this.p = 2
   }
}
class B extends A {
   get m() {
     return super.p;
   }
}
let b = new B()
b.m  // undefined

上面代碼中旦棉,p是父類A實(shí)例的屬性齿风,super.p就引用不到它。
如果屬性定義在父類的原型對象上绑洛,super就可以取到救斑。

class A {}
A.prototype.x = 2
class B extends A {
   constructor() {
      super()
      console.log(super.x)  // 2
   }
}
let b = new B()

ES6規(guī)定,在子類普通方法中通過super調(diào)用父類的方法時(shí)真屯,方法內(nèi)部的this指向當(dāng)前的子類實(shí)例脸候。

class A {
   constructor() {
     this.x = 1
  }
  print() {
    console.log(this.x)
  }
}
class B extends A {
   constructor() {
     super()
     this.x = 2
  }
  m() {
    super.print()
  }
}
let b = new B()
b.m()  // 2

上面代碼中,super.print()雖然調(diào)用的是A.prototype.print()绑蔫,但是A.prototype.print()內(nèi)部的this指向子類B的實(shí)例运沦,導(dǎo)致輸出的是2,而不是1配深。也就是說携添,實(shí)際上執(zhí)行的是super.print.call(this)。

由于this指向子類實(shí)例凉馆,所以如果通過super對某個屬性賦值,這時(shí)super就是this亡资,賦值的屬性會變成子類實(shí)例的屬性澜共。

class A {
   constructor() {
      this.x = 1
   }
}

class B extends A {
   constructor() {
      super()
      this.x = 2
     super.x = 3
     console.log(super.x)  // undefined
     console.log(this.x)  // 3
  }
}
let b = new B()

上面代碼中,super.x賦值為3锥腻,這時(shí)等同于對this.x賦值為3嗦董。而當(dāng)讀取super.x的時(shí)候,讀的是A.prototype.x瘦黑,所以返回undefined京革。

如果super作為對象,用在靜態(tài)方法之中幸斥,這時(shí)super將指向父類匹摇,而不是父類的原型對象。

class Parent{
    static myMethod(msg) {
       console.log('static', msg)
    }
    myMethod(msg) {
       console.log('instance', msg)
    }
}

class Child extends Parent {
    static myMethod(msg) {
       super.myMethod(msg)
   }
   myMethod(msg) {
     super.myMethod(msg)
   }
}

Child.myMethod(1)  // static 1
var child = new Child()
child.myMethod(2)  // instance 2

另外甲葬,在子類的靜態(tài)方法中通過super調(diào)用父類的方法時(shí)廊勃,方法內(nèi)部的this指向當(dāng)前的子類,而不是子類的實(shí)例经窖。

注意坡垫,使用super的時(shí)候,必須顯示指定是作為函數(shù)画侣,還是作為對象使用冰悠,否則會報(bào)錯。
class A { }
class B extends A {
   constructor() {
      super()
      console.log(super) //報(bào)錯
   }
}
上面代碼中配乱,console.log(super)當(dāng)中的super溉卓,無法看出是作為函數(shù)使用皮迟,還是作為對象使用,所以JavaScript引擎解析代碼的時(shí)候就會報(bào)錯的诵。這時(shí)万栅,如果能清晰地表明super的數(shù)據(jù)類型,就不會報(bào)錯西疤。

4烦粒、類的prototype屬性和proto屬性
Class作為構(gòu)造函數(shù)的語法糖,同時(shí)有prototype屬性和proto屬性代赁,因此同時(shí)存在兩條繼承鏈扰她。
(1)子類的proto屬性,表示構(gòu)造函數(shù)的繼承芭碍,總是指向父類徒役。
(2)子類prototype屬性的proto屬性,表示方法的繼承窖壕,總是指向父類的prototype屬性忧勿。

class A { }
class B extends A { }
B._proto_ === A // true
B.prototype._proto_ === A.prototype // true

上面代碼中,子類B的_proto_屬性指向父類A瞻讽,子類B的prototype屬性的_proto_屬性指向父類A的prototype屬性鸳吸。

 class A { }
 class B { }

 // B的實(shí)例繼承A的實(shí)例
 Object.setPrototypeOf(B.prototype, A.prototype)
// B 繼承 A的靜態(tài)屬性
 Object.setPrototypeOf(B, A)
 const b = new B()

Object.setPrototypeOf(B.prototype, A.prototype)
// 等同于
B.prototype._proto_ = A.prototype

Object.setPrototypeOf(B, A)
// 等同于
B._protot_ = A;

這兩條繼承鏈,可以這樣理解:作為一個對象速勇,子類(B)的原型(proto屬性)是父類(A)晌砾;作為一個構(gòu)造函數(shù),子類(B)的原型對象(prototype屬性)是父類的原型對象(prototype屬性)的實(shí)例烦磁。

B.prototype = Object.create(A.prototype)
//等同于
B.prototype._proto_ = A.prototype

原文鏈接:https://es6.ruanyifeng.com/#docs/class-extends

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末养匈,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子都伪,更是在濱河造成了極大的恐慌呕乎,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件陨晶,死亡現(xiàn)場離奇詭異楣嘁,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)珍逸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進(jìn)店門逐虚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人谆膳,你說我怎么就攤上這事叭爱。” “怎么了漱病?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵买雾,是天一觀的道長把曼。 經(jīng)常有香客問我,道長漓穿,這世上最難降的妖魔是什么嗤军? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮晃危,結(jié)果婚禮上叙赚,老公的妹妹穿的比我還像新娘。我一直安慰自己僚饭,他們只是感情好震叮,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鳍鸵,像睡著了一般苇瓣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上偿乖,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天击罪,我揣著相機(jī)與錄音,去河邊找鬼贪薪。 笑死媳禁,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的古掏。 我是一名探鬼主播损话,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼侦啸,長吁一口氣:“原來是場噩夢啊……” “哼槽唾!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起光涂,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤庞萍,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后忘闻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钝计,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年齐佳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了私恬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡炼吴,死狀恐怖本鸣,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情硅蹦,我是刑警寧澤荣德,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布闷煤,位于F島的核電站,受9級特大地震影響涮瞻,放射性物質(zhì)發(fā)生泄漏鲤拿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一署咽、第九天 我趴在偏房一處隱蔽的房頂上張望近顷。 院中可真熱鬧,春花似錦艇抠、人聲如沸幕庐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽异剥。三九已至,卻和暖如春絮重,著一層夾襖步出監(jiān)牢的瞬間冤寿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工青伤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留督怜,地道東北人。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓狠角,卻偏偏與公主長得像号杠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子丰歌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評論 2 354

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

  • (一) set 數(shù)據(jù)結(jié)構(gòu) ES6 提供了新的數(shù)據(jù)結(jié)構(gòu) Set姨蟋。它類似于數(shù)組,但是成員的值都是唯一的立帖,沒有重復(fù)的值眼溶。...
    woow_wu7閱讀 1,075評論 1 1
  • 簡介 Class 可以通過extends關(guān)鍵字實(shí)現(xiàn)繼承,這比 ES5 的通過修改原型鏈實(shí)現(xiàn)繼承晓勇,要清晰和方便很多堂飞。...
    硅谷干貨閱讀 186評論 0 0
  • 簡介 Class可以通過extends關(guān)鍵字實(shí)現(xiàn)繼承。 上面代碼定義了一個ColorPoint類绑咱,該類通過exte...
    oWSQo閱讀 668評論 0 1
  • 一绰筛、簡介 Class 可以通過 extends 關(guān)鍵字實(shí)現(xiàn)繼承,這比 ES5 通過修改原型鏈實(shí)現(xiàn)繼承更加清晰和方便...
    了凡和纖風(fēng)閱讀 618評論 0 0
  • 簡介 Class 可以通過extends關(guān)鍵字實(shí)現(xiàn)繼承描融,這比 ES5 的通過修改原型鏈實(shí)現(xiàn)繼承铝噩,要清晰和方便很多。...
    emmet7life閱讀 357評論 0 0