iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 7
0
Modern Web

ngrx/store 4 學習筆記系列 第 7

[ngrx/store-7] 純函數 (Pure Function)

純函數(Pure Function)

定義

根據 Wikipedia 的定義,一個函數稱為純函數需要符合下列兩個條件:

  1. 函數對於同樣的參數,永遠產生同樣的結果,也就是這個函數不能根據一些隱藏資訊(例如函數內使用全域變數,亂數...)或者目前的狀態在程式執行時(例如目前時間,目前頁面...),程式與程式之間 (在不同的函數呼叫此函數時),或者使用者輸出入介面(I/O)的值(例如 event listener對於 input, mouseMove, 跟後端伺服器做 request...)。
  2. 函數產生的結果,不能帶來副作用(side effect)或者輸出,也就是不能對可變動的物件(mutable object)做更動,或者使用者輸出介面做輸出。

副作用

這個副作用的觀念相當重要,會產生副作用的函數對我們的影響是

  • **測試變得複雜:**因為有外在的因素,測試的考慮需要更多,例如對於後端的需求,因為有可能伺服器的問題,可能網路的問題... 造成我們要設不同的條件來做測試
  • **除錯不易:**例如用到全域變數,當這個全域變數因為某種因素變化時,函數產生的結果也變得不同,也就可能造成在不同的執行情況下,不同的結果造成跟設想的結果不同而一頭霧水
  • 重構(refactor) 不易:當相同的函數用不同的寫法稱為重構(refactor), 通常重構發生於例如 Library 版本不同時,或者使用不同的架構時(由 service 改為 store),因為要考慮到所有的副作用,重構會變成一項大工程。

然而我們也不可能都用純函數,因為我們總要對使用者的輸入做反應,對後端的 request 做反應,為此,這種分別在 ngrx/store 切得很清楚,凡是 reducer 函數一定是純函數 pure function, 而會產生副作用的地方,我們都將它們放在 ngrx/effects 中,這樣在大型專案中,我們可以很清楚要怎樣做重構或者測試。

純函數的例子

我們來看幾個純函數的例子

function sum(a, b) {
  return a + b;
}
sum(2,5);
// will always return 7

Math.sin(0.5)
// will always return 0.4794...

不純函數的例子

使用外來變數

var discount = 0.8;

function calcPrice(price) {
  return price * discount;
}

console.log(calcPrice(100));
// will return 80
// however when discount var change
var discount = 0.9;

console.log(calcPrice(100));
// now will return 90

使用亂數或者目前時間

// random variable
function getValue() {
  return Math.random();
}

console.log(getValue());
// will always return different number

// current time
function getTime() {
  return new Date().toISOString();
}

console.log(getTime());
// return current time
setTimeout(() => {
  console.log(getTime());
}, 1000);
//return another time

最後這個例子更改了可變物件

// javascript mutable object
const person = {name: 'Joe', age: 20, title: 'Engineer'};

function changeTitle(p) {
  p.title = 'Manager';
}

changeTitle(person);
console.log(person);
// will be {name: 'Joe', age: 20, title: 'Manager'}

所有例子在 codepen

在 Javascript 中,有些變數型態是不可變的(immutable), 有些是可變的(mutable).
在 Reducer 中為了要保持純函數,我們不能將一個狀態直接更改它的屬性(property),而需要將原狀態拷貝一份,再將新的這一份拷貝的屬性改成新的值。要怎麼做呢?我們下次來談這個部分。


上一篇
[ngrx/store-6] Flux 的基本概念
下一篇
[ngrx/store-8] Javascript Mutable 跟 Immutable 資料型態
系列文
ngrx/store 4 學習筆記30

尚未有邦友留言

立即登入留言