JavaScript 純函數

純函數

第一次據說"純函數(Pure Function)"這個術語時, 我也是比較疑惑的. 啥是純函數? 爲何要使用純函數? 以及和普通的JavaScript函數有什麼區別嗎?編程

帶着這些疑問, 一塊兒來看下.markdown

什麼是純函數?

定義

  • 若是函數的調用參數相同, 則永遠返回相同的結果. 它不依賴於程序執行期間函數外部任何狀態或數據的變化, 只依賴於傳入的參數
  • 純函數不會產生任何可觀察的反作用, 例如: 網絡請求, 輸入/輸出設備, 或數據突變(mutation)等

若是一個函數符合上述2個要求, 它就是純函數.網絡

什麼是可觀察的反作用?

一個能夠被觀察的反作用是在函數內部與該函數外部的任意交互. 如: 在函數內修改外部的變量, 或在函數內調用另一個函數等等.dom

若是純函數調用純函數, 不會產生反作用, 依然是純函數函數式編程

可被觀察的反作用, 包括但不限於:函數

  • 進行一個HTTP請求
  • Mutating Data
  • 輸出數據到屏幕或控制檯
  • DOM 查詢或操做
  • Math.random()
  • 獲取當前時間
  • ...

反作用自己並無什麼很差, 在某些場景每每是必需的. 但對於要保持純函數, 它不能包含任何反作用. 固然, 並不是全部函數都必須是純函數.oop

純函數 示例

function sqrt(a) {
  return a * a
}
複製代碼

該函數符合咱們所說的2條純函數的定義, 不依賴於任何外部輸入, 不改變任何外部數據, 沒有反作用. 每次輸入一樣的參數, 永遠會獲取相同的結果, 且不隨程序執行的時機而有變化.單元測試

非純函數 示例

function getName(obj){    
  return obj.name;
}
function getAge(obj){  
  return obj.age;
}
function sayHi(person){  
  console.log('I am' + getName(person) + ',and I am' + getAge(person) + 'years old');
  }
  
var Tom = {  name: 'TOM',  age: 26};

sayHi(Tom);
複製代碼

sayHi不是純函數,它依賴於getNamegetAge兩個函數,若不當心或因業務須要, 必須要改變其中某個函數的功能,這將使得sayHi這個函數出現錯誤。 當網頁變得複雜,且由多人維護的時候,bug調試會變得很是複雜。測試

純函數的優勢

純函數在函數式編程中被大量使用, 諸如React.jsRedux等庫都須要使用純函數.ui

純函數能夠用在日常的JavaScript開發中使用, 也能夠混合純函數和非純函數一塊兒使用, 不必定非要限定某個編程範例中必須使用純函數.

並不是全部的函數都須要純函數. 例如: 操做DOM的事件處理函數就不適合使用純函數. 不過, 這種事件處理函數, 能夠調用其餘純函數來處理, 以此減小項目中不純函數的數量.

使用純函數的主要緣由是可測試性和重構

可測試性

純函數很是容易進行單元測試,由於不須要考慮上下文環境,只須要考慮輸入和輸出, 若是傳入相同的參數, 它們將始終產生相同的結果.

重構

純函數還會使得維護和重構代碼變容易.

你能夠放心的重構一個函數, 沒必要擔憂沒注意到的反作用, 而致使整個應用調試複雜/困難.

::: warning 若是項目中, 充斥着反作用, 那麼函數/模塊之間的邏輯可能互相交織耦合, 在後期新增邏輯時, 可能因爲依賴複雜而難以重構.

更常見的是, 開發爲了應付需求, 而不斷引入新的反作用到本來的邏輯上, 從而致使代碼變得愈來愈糟糕. :::

正確地使用純函數, 能夠生產更高質量的代碼, 而且也是一種更加乾淨的編碼方式.

此外, 純函數不是JavaScript的專利. 想要了解更多內容, 能夠查閱PureFunction-wiki

可移植性 / 自文檔化(Portable / Self-Documenting)

因爲純函數是自給自足的,它須要的東西都在輸入參數中已經聲明,因此它能夠任意移植到任何地方。

相關連接

相關文章
相關標籤/搜索