iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 9
2

在 javaScript 世界中我們可以把 function 區分為

Impure Function

  • 有回傳但也有 Side Effect
  • 沒有回傳

Pure Function:

遵守 one input, one output 原則,不管輸入幾次同樣值,輸出結果永遠相同。只做運算與回傳 return,而且不對外部世界造成任何改變 ( 沒有 Side Effect)

// -- Pure function --
const greet = (name) => {
	return `Hi, I am ${name}`
}
greet('Hannah') // Hi, I'm Hannah

// -- Below all impure function --
// 沒有回傳值
const greet = (name) => {
  console.log(`Hi, I am ${name}`);
}

// 有回傳值,但也有 Side Effect
let count = 0;

const greet = (name) => {
  count++;
  return `Count ${name} ${count}`; 
}

這篇也總結前面所有 Buzz words,看似一團亂的專有名詞其實都是相關連的。
https://ithelp.ithome.com.tw/upload/images/20200909/20106426EjJIJIHugz.jpg
Pure Function 裡面 data 多是 immutable data 與 stateless (avoid share state) 的。另外當一個函式是 pure function 且不依賴任何外部狀態只依賴函式參數,也稱作 referential transparency (引用透明)。
https://ithelp.ithome.com.tw/upload/images/20200909/201064267tppKp6RPO.jpg

要如何知道自己寫的 function 有沒有 Pure,也可以從以下三點來檢視

Total

不管輸入什麼值 (input) 都一定會有相對應的結果 output

❌  // Not total,測試 count(5) 就 GG
const count = i => {
	if(i===0) return 0;
	if(i===1) return 1;
	if(i===2) return 2
}

✅ // 不管輸入什麼都會有相對應的值
const count = i => {
	if(i===0) return 0;
	if(i===1) return 1;
	if(i===2) return 2
    return 100;
}

const count = i => i

Deterministic 穩定的

❌
var x = 1;
var result = () => x++
result() // 2
result() // 3
result() // 4

✅
const result = y => y + 1;
result(1) // 2
result(1) // 2
result(1) // 2

No Observable Side-Effects

儘管 JavaScript 世界中,們很難完全避掉但可以運用一些技巧來控管 Side Effect,讓 Side Effect 只作用在一定的範圍內,不要出現預期外的 side effect 以確保我們的程式碼能順利運行且穩定的!

❌
const add = (x, y) => {
    console.log(`Adding ${x} ${y}`)
    return x + y
}

✅
const add = (x, y) => {
    return {result: x + y, log: `Adding ${x} ${y}`}
}

Stateless (Avoid share state)

不依賴任何外部狀態只依賴函式參數

❌ // impure
var minimum = 21;

var checkAge = function(age) {
  return age >= minimum;
};

✅ // pure
var checkAge = function(age) {
  var minimum = 21;
  return age >= minimum;
};

用 Pure Function 好處

Easy 容易理解

當我們把功能拆解成小單位的 function 再進行封裝跟組合,程式碼都可以變的很乾淨且容易理解。

let transform1 = pipe(
  isString, // 是否字串
  toUpper, // 全部大寫
  exclaim // 最後加 !
)('hello world')

/*
> 'hello world'
  |> 'hello world'
  |> 'HELLO WORLD'
  |> 'HELLO WORLD !'
*/

Reliable 可靠穩定的 & 可並行運作

Pure Function 同輸入同輸出的特性,是可以預期的且非常穩定的,且不依賴任何外部狀態所以若要 Refactor 或 debug 也比傳統寫法容易很多。

Testable 可測試

因 Pure Function 有高預測性,所以非常容易被測試。也不需要去煩惱會受到其他 Scope 的干擾,只有輸入值才會導致改變

Reusable 再利用 & Portable

他不會 stuck environment,換個專案可以整包繼續用,因為不受外在環境影響 、可重覆使用性高

Composable 再組合

因為 Function 在 js 是 First Class 所以可以衍伸出各式各樣非常好用的寫法,最著名之一就是 Compose,接下來篇章也會說到這個


參考文章

如有錯誤或需要改進的地方,拜託跟我說。
我會以最快速度修改,感謝您

上一篇
Buzz word 4 : Stateless
下一篇
[練習] 玩轉 pure/impure function
系列文
Functional Programming in JS30

2 則留言

0
YNCBearz
iT邦新手 5 級 ‧ 2020-09-09 12:49:13

想請教pure funcion的概念,是否類似撰寫unit testing,
透過消除對外部的依賴,只留下純粹的邏輯?

自己理解的對應關係:

函式的世界 測試的世界
Inpure Function Integrated Testing
Pure Function Unit Testing
hannahpun iT邦新手 5 級 ‧ 2020-09-09 15:36:28 檢舉

以我理解不太能這樣分,因為 unit test 的確通常是以 function 為單位
Integrated 是整合測試,但有可能發生 unit test 沒問題但在 Integration test 時發生錯誤
自己曾經寫過一篇文 裡面的那一張圖 "窗戶本身沒問題但整合時有問題" 可以很清楚看到這兩者之區別 XD

YNCBearz iT邦新手 5 級 ‧ 2020-09-09 16:16:04 檢舉

謝謝你的回應,我再多想想

0
sliceart
iT邦新手 5 級 ‧ 2020-09-14 11:20:18

以下為個人觀點,可能也有錯誤之處
盡信書不如無書,謝謝


單元測試與pure function是兩件不同的事情,不應該也不需要一起比較,因為它們要解決的問題是不一樣的

常常聽到的一次只測一件事情,隔離外部相依性因就是希望讓他成為最小的測試單元,如此一來當測試失敗,你會很容易知道是哪一個地方出錯

如果不管這件事情,只是將所有的外部依賴拉掉,那單元測試失敗後,能知道是哪一個地方錯誤嗎?

Pure Function 如同 Hannah 先前說的,確保相同的輸入,都有相同的輸出,就程式碼的可閱讀性來說是天然優勢,不僅好理解也好維護

所以我個人認為,pure function帶來的優點包含:可重複利用、程式碼好理解、便於維護;當然pure function更容易寫單元測試
因為我也正在看hannah的文章學習FP,所以pure function的優點還是看文章吧

單元測試的優點我覺得除了你Google搜尋到的一堆以外,那些好處你自己去google就行了,另外一個很重要的是對於你自己開發時期的信心建立,你能夠用baby step確保每一個步驟走的都是踏實的。

通常會接觸到單元測試,下一步就是TDD,講到TDD就不能不提91的30天系列,你會對於單元測試有疑慮的話,去看看吧

我要留言

立即登入留言