為什么要寫(xiě)super(props)

用React開(kāi)發(fā)class組件時(shí)轧苫,constructor中一定要調(diào)用 super(props)樟遣。

下面通過(guò)兩個(gè)問(wèn)題逐步分析茧妒。第一:為什么要調(diào)用super?第二:為什么要傳入props祠丝,不傳會(huì)發(fā)生什么疾呻?

首先解釋第一個(gè)問(wèn)題:

在 JavaScript 子類(lèi)的構(gòu)造函數(shù)中 super 指的是父類(lèi)(即超類(lèi))的構(gòu)造函數(shù)。子類(lèi)中顯式定義了constructor的方法中必須在其最頂層調(diào)用super写半,否則新建實(shí)例時(shí)會(huì)報(bào)錯(cuò)。這是因?yàn)樽宇?lèi)自己的this對(duì)象尉咕,必須先通過(guò)父類(lèi)的構(gòu)造函數(shù)完成塑造叠蝇,得到與父類(lèi)同樣的實(shí)例屬性和方法,然后再對(duì)其進(jìn)行加工年缎,加上子類(lèi)自己的實(shí)例屬性和方法悔捶。如果不調(diào)用super方法,子類(lèi)就得不到this對(duì)象单芜。所以必須先調(diào)用super才可以使用this蜕该。如果子類(lèi)沒(méi)有定義constructor方法,這個(gè)方法會(huì)被默認(rèn)添加洲鸠。

如下:

class A {}

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

new B().constructor === B // true

以上結(jié)論證明super雖然代表了父類(lèi)A的構(gòu)造函數(shù)堂淡,但是返回的是子類(lèi)B的實(shí)例,即super內(nèi)部的this指的是B的實(shí)例扒腕,因此super()相當(dāng)于A.prototype.constructor.call(this)绢淀。

再通過(guò) new.target 驗(yàn)證:

class A {
  constructor() {
    console.log(new.target.name);
  }
}

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

new B() // B

new.target指向new命令作用的構(gòu)造函數(shù),以上 new.target.name 為 B瘾腰,由此可知在super()執(zhí)行時(shí)皆的,它指向的是子類(lèi)B的構(gòu)造函數(shù),而不是父類(lèi)A的構(gòu)造函數(shù)蹋盆。也就是說(shuō)费薄,super()內(nèi)部的this指向的是B。

在React中栖雾,super指向了 React.Component楞抡,所以在調(diào)用父類(lèi)的構(gòu)造函數(shù)之前,是不能在 constructor 中使用 this 關(guān)鍵字的岩灭。

class Button extends React.Component {
  constructor() {
    // 還不能訪(fǎng)問(wèn) `this`
    super();
    // 可以訪(fǎng)問(wèn)
    this.state = { show: true }
  }
  // ...
}

第二個(gè)問(wèn)題拌倍,為什么要傳props?

為了讓 React.Component 構(gòu)造函數(shù)初始化 this.props。React源碼是這樣的:

function Component(props, context) {
  this.props = props;
  this.context = context;

  // ...
}

但是有些時(shí)候在調(diào)用 super() 的時(shí)即使沒(méi)有傳入 props柱恤,依然能夠在 render 函數(shù)或其他方法中訪(fǎng)問(wèn)到 this.props数初。那這是怎么做到的呢?事實(shí)證明梗顺,React 在調(diào)用構(gòu)造函數(shù)后也立即將 props 賦值到了實(shí)例上:

// React 內(nèi)部
const instance = new YourComponent(props);
instance.props = props;

所以即便忘記了將 props 傳給 super()泡孩,React 也仍然會(huì)在之后將它定義到實(shí)例上。這樣做是有原因的:

當(dāng) React 增加了對(duì)類(lèi)的支持時(shí)寺谤,不僅增加了對(duì)ES6類(lèi)的支持仑鸥。其目標(biāo)是盡可能廣泛的支持類(lèi)抽象。當(dāng)時(shí)尚不清楚 ClojureScript变屁,CoffeeScript眼俊,ES6,F(xiàn)able粟关,Scala.js疮胖,TypeScript 或其他解決方案在類(lèi)組件方面是否成功。因此 React 刻意地沒(méi)有顯式要求調(diào)用 super()闷板。

那是不是意味著能夠用 super() 代替 super(props) 嗎澎灸?

最好不要這樣做,這樣寫(xiě)在邏輯上并不能確定沒(méi)問(wèn)題遮晚,因?yàn)镽eact 會(huì)在構(gòu)造函數(shù)執(zhí)行完畢之后才給 this.props 賦值性昭。但這樣做會(huì)使得 this.props 在 super 調(diào)用一直到構(gòu)造函數(shù)結(jié)束期間值為 undefined。

class Button extends React.Component {
  constructor(props) {
    super();  // 忘了傳入 props
    console.log(props);      // {}
    console.log(this.props); // undefined
  }
  // ...
}

如果在構(gòu)造函數(shù)中調(diào)用了內(nèi)部的其他方法县遣,那么一旦出錯(cuò)這會(huì)使得調(diào)試過(guò)程阻力變大糜颠。這就是為什么建議開(kāi)發(fā)者一定執(zhí)行 super(props) 的原因。

class Button extends React.Component {
  constructor(props) {
    super(props) // 傳入 props
    console.log(props)      // {}
    console.log(this.props) // {}
  }

  // ...
}

這樣就確保了 this.props 在構(gòu)造函數(shù)執(zhí)行完畢之前已被賦值艺玲。

此外括蝠,還有一點(diǎn)是 React 開(kāi)發(fā)者長(zhǎng)期以來(lái)的好奇之處。

當(dāng)在組件中使用Context API 的時(shí)候饭聚,context會(huì)作為第二個(gè)參數(shù)傳入constructor忌警,那么為什么我們不寫(xiě)成 super(props, context) 呢?可以秒梳,但 context 的使用頻率較低法绵,因而沒(méi)有必要。

而且 class fields proposal 出來(lái)后酪碘,在沒(méi)有顯示定義構(gòu)造函數(shù)的情況下朋譬,以上屬性都會(huì)被自動(dòng)地初始化。使得像 state = {} 這類(lèi)表達(dá)式能夠在需要的情況下引用 this.propsthis.context 的內(nèi)容:

class Button extends React.Component {
  state = {
    age: this.props.age,
    name: this.context.name
  }

  // ...
}

當(dāng)然兴垦,有了 Hooks 以后徙赢,幾乎就不需要 super 和 this 了字柠,但那就是另一個(gè)概念了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末狡赐,一起剝皮案震驚了整個(gè)濱河市窑业,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌枕屉,老刑警劉巖常柄,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異搀擂,居然都是意外死亡西潘,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)哨颂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)喷市,“玉大人,你說(shuō)我怎么就攤上這事咆蒿《ǎ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵沃测,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我食茎,道長(zhǎng)蒂破,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任别渔,我火速辦了婚禮附迷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘哎媚。我一直安慰自己喇伯,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布拨与。 她就那樣靜靜地躺著稻据,像睡著了一般。 火紅的嫁衣襯著肌膚如雪买喧。 梳的紋絲不亂的頭發(fā)上捻悯,一...
    開(kāi)封第一講書(shū)人閱讀 51,604評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音淤毛,去河邊找鬼今缚。 笑死,一個(gè)胖子當(dāng)著我的面吹牛低淡,可吹牛的內(nèi)容都是我干的姓言。 我是一名探鬼主播瞬项,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼何荚!你這毒婦竟也來(lái)了囱淋?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤兽泣,失蹤者是張志新(化名)和其女友劉穎绎橘,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體唠倦,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡称鳞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了稠鼻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冈止。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖候齿,靈堂內(nèi)的尸體忽然破棺而出熙暴,到底是詐尸還是另有隱情,我是刑警寧澤慌盯,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布周霉,位于F島的核電站,受9級(jí)特大地震影響亚皂,放射性物質(zhì)發(fā)生泄漏俱箱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一灭必、第九天 我趴在偏房一處隱蔽的房頂上張望狞谱。 院中可真熱鬧,春花似錦禁漓、人聲如沸跟衅。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)伶跷。三九已至,卻和暖如春荚恶,著一層夾襖步出監(jiān)牢的瞬間撩穿,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工谒撼, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留食寡,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓廓潜,卻偏偏與公主長(zhǎng)得像抵皱,于是被迫代替她去往敵國(guó)和親善榛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355