在介紹本篇我們先來複習一下先前在 pure function 那章提過的一些名詞
但在現實開發中則無法避免這些 Side Effect 的操作,舉幾個例子,
localStorage
,console
,new Date
),Math.random
),所以今天就要講講在 Functional Programming 中,如何去處理這些 side effect
example
在還沒開始介紹 IO 前,先來看看原本我們是如何寫出 pure function, 沒錯,就是 dependency injection.
假設現在有一個函式,其功用是要取得 document.body
的高度,
function getBodyOffsetHeight() {
return document.querySelector('body').offsetHeight;
}
const offSetHeight = getBodyOffsetHeight();
可以看到 getBodyOffsetHeight
是一個 impure function,因為 DOM 有可能隨時改變,會使得每次呼叫 getBodyOffsetHeight
結果有可能會不一樣,要如何把它變成 pure function 呢?
function getBodyOffsetHeightFromDOM($) {
return $('body').offsetHeight;
}
const qs = document.querySelector.bind(document);
const offSetHeight = getBodyOffsetHeightFromDOM(qs);
沒錯,可以直接把 document 直接當參數進行傳入,這樣就可以確保給定一樣的輸入就會有得到相同的輸出,這樣不就是一個 pure function 了嘛!!
advantage
這種方法的好處是讓我們在進行 unit test 時,可以不用模擬一個專門測試的 DOM (ex: JSDOM),也就是讓程式可可測試性增加。
const mockQS = () => ({ offsetHeight: 1000 });
const offSetHeight = getUserNameFromDOM(mockQS);
assert.strictEqual(offSetHeight, 1000, true)
disadvantage
雖然我們確保了函式是 pure function 跟可測試,但當我們是開發一個大型的 App,則導致 App 非常難以維護及閱讀。
舉例來說,由於函式要 pure, 所以我們在最外層的 function 注入所有需要的的 dependency,但如果這個函式裡面是非常深層的,就必須要將參數不斷傳遞,這將會導致我們的程式碼非常難以維護。
const App = ($, localStorage, date, config, ... ) => {
/** prop drilling */
}
今天因為考駕照太忙了,所以將原訂計畫稍加更改,明天將來介紹 IO Monad 是如何處理 Side Effect 的!
感謝大家閱讀!
NEXT: Handle Side Effect - IO Monad