從 React 綁定 this,看 JS 語言發展和框架設計

在 javascript 語言中,關於 this 這個關鍵字的行為一直以來困擾著一代又一代初級開發者。同時 this,也充分反應了 javascript 的詭異與靈活。

但是請別誤會,這篇文章並不會對 this 的特徵進行全方位講解,因為這些內容都可以在各種前端書籍中找到答案。這裡,我試圖結合 React 事件處理函數關於 this 綁定的演化史,談一談這個框架設計以及 javascript 語言在這一細節上的進步和完善。同時對比 this 綁定的不同方案,讓大家對 React 、ES next 有一個更清晰的認識。

  • React.createClass 自動綁定;
  • 渲染時綁定;
  • 箭頭函數綁定;
  • Constructor 內綁定;
  • Class 屬性中使用 = 和箭頭函數

方法一:React.createClass 自動綁定

React 中創建組件的方式已經很多,比較古老的諸如 React.createClass 應該很多人並不陌生。當然,從 React 0.13 開始,可以使用 ES6 Class 代替 React.createClass 了,這應該是今後推薦的方法。 但是需要知道,React.createClass 創建的組件,可以自動綁定 this。也就是說,this 這個關鍵字會自動綁定在組件實例上面。

// This magically works with React.createClass
// because `this` is bound for you.
onChange = {this.handleChange}

當然很遺憾,對於組件的創建,官方已經推薦使用 class 聲明組件或使用 functional 無狀態組件


方法二:渲染時綁定

通過前文,我們知道最傳統的組件創建方式不會有 this 綁定的困擾。接下來,我們假定所有的組件都採取 ES6 classes 方式聲明。這種情況下,this 無法自動綁定。一個常見的解決方案便是:

onChange = {this.handleChange.bind(this)}

這種方法簡明扼要,但是有一個潛在的性能問題:當組件每次重新渲染時,都會有一個新的函數創建。OMG! 這聽上去貌似是一個很大的問題,但是其實在真正的開發場景中,由此引發的性能問題往往不值一提(除非是大型組件消費類應用或遊戲)。


方法三:箭頭函數綁定

這種方法其實和第二種類似,拜 ES6 箭頭函數所賜,我們可以隱式綁定 this

onChange = {e => this.handleChange(e)}

當然,也與第二種方法一樣,它同樣存在潛在的性能問題。下面將要介紹的兩種方法,可以有效規避不必要的性能消耗,請繼續閱讀。


方法四:Constructor 內綁定

constructor 方法是類的默認方法,通過new命令生成對象實例時,自動調用該方法。 所以我們可以:

constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}

這種方式往往被推薦為“最佳實踐”,也是筆者最為常用的方法。 但是就個人習慣而言,我認為與前兩種方法相比,constructor 內綁定在可讀性和可維護性上也許有些欠缺。 同時,我們知道在 constructor 聲明的方法不會存在實例的原型上,而屬於實例本身的方法。每個實例都有同樣一個 handleChange,這本身也是一種重複和浪費。 如果你對 ES next 一直抱有開放的思想,且能夠使用 stage-2 的特性,不妨嘗試一下最後一種方案。


方法五:Class 屬性中使用 = 和箭頭函數

handleChange = () => {
// call this function from render
// and this.whatever in here works fine.
};

我們來總結一下這種方式的優點:

【1】使用箭頭函數,有效綁定了 this;

【2】沒有第二種方法和第三種方法的潛在性能問題;

【3】避免了方法四的組件實例重複問題;

【4】 我們可以直接從 ES5 createClass 重構得來。


總結

本文在對比 React 綁定 this 的五種方法的同時,也由遠及近了解了 javascript 語言的發展:從 ES5 的 bind, 到 ES6 的箭頭函數,再到 ES next 對 class 的改進。 React 作為蓬勃發展的框架也同樣在與時具進,不斷完善,結合語言特性的發展不斷調整著自身。 最後,我們通過這張圖片來完整回顧:

從 React 綁定 this,看 JS 語言發展和框架設計


分享到:


相關文章: