作者:王少飛
在做業務時我們用 react + redux 架構,其中 redux 的 reducers 是用的純函數。這裡什麼是純函數?為什麼要用純函數?純函數的好處是什麼?接下來的我們一起研究下。
redux 強調 reducers 一定要是純函數

滿足以上兩條的函數成為純函數:
在相同的輸入值時,需産生相同的輸出。函數的輸出和輸入值以外的其他隐藏資訊或狀态無關,也和由I/O裝置産生的外部輸出無關
不能有語義上可觀察的函數副作用,諸如“觸發事件”,使輸出裝置輸出,或更改輸出值以外物件的内容等
圖一中<code>slice</code>函數在相同的輸入時,輸出總是一樣的,并且<code>arr</code>并沒有改變,是以是純函數
圖二中<code>splice</code>函數在輸入相同是,輸出并不相同,并且<code>arr</code>發生了改變,是以是非純函數
如下圖所示,如果我們把reducers的純函數修改為不純的函數:
純函數的代碼
修改為不純的函數,我們在reducer内修改了舊的state變量
下面來看下redux是如何處理的
reducer将舊的狀态(prev)和要修改的資料一起傳進去,然後傳回一個新的(next)狀态,prev和next相比較來确定storge資料是否改變。如果我們用不純的函數,prev和next将一緻,就算資料改變,hasChanged也會是false。
維基百科的解釋不太通俗,我們來看下他具有那些特點:
函數是"第一等公民"
所謂"第一等公民"(first class),指的是函數與其他資料類型一樣,處于平等地位,可以指派給其他變量,也可以作為參數,傳入另一個函數,或者作為别的函數的傳回值。
隻用"表達式",不用"語句"
"表達式"(expression)是一個單純的運算過程,總是有傳回值;"語句"(statement)是執行某種操作,沒有傳回值。函數式程式設計要求,隻使用表達式,不使用語句。也就是說,每一步都是單純的運算,而且都有傳回值。
原因是函數式程式設計的開發動機,一開始就是為了處理運算(computation),不考慮系統的讀寫(I/O)。"語句"屬于對系統的讀寫操作,是以就被排斥在外。
當然,實際應用中,不做I/O是不可能的。是以,程式設計過程中,函數式程式設計隻要求把I/O限制到最小,不要有不必要的讀寫行為,保持計算過程的單純性。
沒有"副作用"
所謂"副作用"(side effect),指的是函數内部與外部互動(最典型的情況,就是修改全局變量的值),産生運算以外的其他結果。
函數式程式設計強調沒有"副作用",意味着函數要保持獨立,所有功能就是傳回一個新的值,沒有其他行為,尤其是不得修改外部變量的值。
不修改狀态
上一點已經提到,函數式程式設計隻是傳回新的值,不修改系統變量。是以,不修改變量,也是它的一個重要特點。
在其他類型的語言中,變量往往用來儲存"狀态"(state)。不修改變量,意味着狀态不能儲存在變量中。函數式程式設計使用參數儲存狀态。
引用透明
引用透明(Referential transparency),指的是函數的運作不依賴于外部變量或"狀态",隻依賴于輸入的參數,任何時候隻要參數相同,引用函數所得到的傳回值總是相同的。
有了前面的第三點和第四點,這點是很顯然的。其他類型的語言,函數的傳回值往往與系統狀态有關,不同的狀态之下,傳回值是不一樣的。這就叫"引用不透明",很不利于觀察和了解程式的行為。
從後面三點可以看出:函數式程式設計要求函數也會是純函數。
傳統的程式設計語言可能是這樣
函數式程式設計是這樣:
看下它有哪些好處:
代碼簡潔,開發快速
函數式程式設計大量使用函數,減少了代碼的重複,是以程式比較短,開發速度較快。
接近自然語言,易于了解
函數式程式設計的自由度很高,可以寫出很接近自然語言的代碼。
更友善的代碼管理
函數式程式設計不依賴、也不會改變外界的狀态,隻要給定輸入參數,傳回的結果必定相同。是以,每一個函數都可以被看做獨立單元,很有利于進行單元測試(unit testing)和除錯(debugging),以及子產品化組合。
易于"并發程式設計"
函數式程式設計不需要考慮"死鎖"(deadlock),因為它不修改變量,是以根本不存在"鎖"線程的問題。不必擔心一個線程的資料,被另一個線程修改,是以可以很放心地把工作分攤到多個線程,部署"并發程式設計"(concurrency)。
函數式程式設計深入了解(待續)
原文連結:http://ivweb.io/topic/58b41ab1aece9f5950397f07