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

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

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

React 處理 this 上下文環境已經有至少五年曆史了。五年期間,方案輩出,咱們先來總結一下。

java

方法一:React.createClass 自動綁定

React 中建立組件的方式已經不少,比較古老的諸如 React.createClass 應該不少人並不陌生。固然,從 React 0.13 開始,可使用 ES6 Class 代替 React.createClass 了,這應該是從此推薦的方法。
可是須要知道,React.createClass 建立的組件,能夠自動綁定 this。也就是說,this 這個關鍵字會自動綁定在組件實例上面。react

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

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

Later, classes were added to the language as part of ES2015, so we added the ability to create React components using JavaScript classes. Along with functional components, JavaScript classes are now the preferred way to create components in React.
For your existing createClass components, we recommend that you migrate them to JavaScript classes. github

我認爲,這實際上是 React 框架自己的自我完善和對將來的迎合,是框架和語言發展的大勢所趨。redux


方法二:渲染時綁定

經過前文,咱們知道最傳統的組件建立方式不會有 this 綁定的困擾。接下來,咱們假定全部的組件都採起 ES6 classes 方式聲明。這種狀況下,this 沒法自動綁定。一個常見的解決方案即是:架構

onChange = {this.handleChange.bind(this)}複製代碼

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


方法三:箭頭函數綁定

這種方法其實和第二種相似,拜 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 屬性中使用 = 和箭頭函數

這個方法依賴於 ES next 的新特性,請參考 tc 39: Public Class Fields

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

咱們來總結一下這種方式的優勢:

  • 使用箭頭函數,有效綁定了 this;
  • 沒有第二種方法和第三種方法的潛在性能問題;
  • 避免了方法四的組件實例重複問題;
  • 咱們能夠直接從 ES5 createClass 重構得來。


總結

本文在對比 React 綁定 this 的五種方法的同時,也由遠及近了解了 javascript 語言的發展:從 ES5 的 bind, 到 ES6 的箭頭函數,再到 ES next 對 class 的改進。

React 做爲蓬勃發展的框架也一樣在與時具進,不斷完善,結合語言特性的發展不斷調整着自身。

最後,咱們經過這張圖片來完整回顧:

各類方式邏輯
各類方式邏輯

本文參考了 Cory House 的文章:5 Approaches for Handling this,並在此基礎上進行延伸。



個人其餘一些關於 React 文章:

Happy Coding!

PS: 做者Github倉庫,歡迎經過代碼各類形式交流。

相關文章
相關標籤/搜索