# React 大小事之 Functional Programming <H3>Functional Programming 是什麼? (簡稱 FP)</H3> 1. 什麼是functional programming ? 基本上 Functional Programming 就是 * Style / Pattern 一種撰寫風格 * Paradigm 一種規範 * Mindset 抽象式思維 所以 FP 不是一種 “程式語言”,也與框架無關,以 JS 來說,不管你是用 Vue、React、Angular、原生 JS 都是可以用 FP 思維去撰寫的。 2. 為何要學? 舊思維不好在哪 * 無法執行 DRY / 很難共用 * 系統難以維護與測試 * 難以閱讀 大家可能都有遇過,小案子寫起來很順沒有什麼太大問題,但當系統越變越複雜,就會發現難以維護、執行 DRY (Don't Repeat Yourself) 很困難、總是花很多時間 debug、不知道怎麼寫測試,甚至出現越改越糟的狀態。 FP 使用大量的 Function,幾乎每個 Function 都可以由更小的 Function 組合出來,好處是可以減少程式碼的重複,所以 FP 的寫法通常比較簡短跟容易。 <h5>FP 精華就是會盡量抽象化 (抽象化時命名很重要,最好是一看函式名稱就知道在做什麼)</h5> 總而言之 FP 就是輕量化程式碼而且容易理解、改變、除錯和具有彈性 <h3>Functional Programming 的使用 </h3> JavaScript 框架就是使用FP來開發程式,因此若想學習 React.js 勢必也要熟悉FP的基本概念,而 JavaScript 程式語言也需要符合FP的編程理念。 了解以下的方法可讓我們更方便開發!! * First-class and higher-order functions * Pure Functions * Declarative vs Imperative <h4>1. First-class and higher-order functions</h4> First-class(一等公民) — 我們可以想像成對待函式(Functions)如同對待其他資料型別一樣。 For example:const a = 1,1 的值也就指定給 a 因此我們也可以直接將函式(Functions)指定給任一變數 For example:const a = (x,y) => x * y,a 也就變成(x * y) Function 的變數,呼叫 a(2, 4) 則會返回值8。 Higher-order functions(高階函式)至少會滿足下列其中一項條件 數學(高階函式)是指至少會滿足下列一項條件的函數 * 接受一個或多個函數作為輸入 * 輸出一個函數 在 FP 的使用上是指 * 可以將函式(至少一個)當成參數傳入另一個函式。 * 可以將函式當成另一個函式的回傳值。 Code example : ``` const add = function(x){ //add函式接收參數並且回傳一個 Function 作為回傳值 return function(y){ return x + y; }; }; const addFive = add(5); const addTen = add(10); addFive(2) // ans : 7 addTen(2) // ans : 12 ``` 從上述範例我們可以得知,add函式接收參數 (x) 並且回傳一個函式 ( x + y ) 作為回傳值。因此在宣告addFive 變數時,同時給定 x=5 至 add 函式,往後使用 addFive 變數(函式變數)皆會從 5 開始加減。 <h4>2. Pure Functions (純函式)</h4> Pure Functions 意指將相同的input丟入函式,永遠會回傳相同的output結果,而且在過程中完全沒有任何的"副作用"。 <h6>" 副作用 ": 通常意味著「避免狀態改變」、「避免資料改變」,我們可以想成不與函式區塊域(block)以外的變數做互動(最典型的例子,修改全域變數的值),或者不論函式以外做了什麼,函式(Functions)內的運算依舊不受改變。</h6> 以JavaScript為例, 副作用有: * 更改外部變數或者物件屬性(例如:全域變數、父類別範圍內的變數等) * 寫入console.log、檔案 * 觸發外部流程 * 呼叫任何有副作用的函式(Functions) 也就是說 Pure Functions擅於純運算,而不做其他事情(例如:讀取外部資料)。 在 FP中,slice 函式(Functions)就符合我們Pure Functions的規範,相同input,永遠回傳相同output且無副作用。而splice函式(Functions)則是每次呼叫,output以及原始資料皆會不相同,因此不算是Pure Functions。 Code example : ``` // slice: Pure Function const arr = [1, 2, 3, 4, 5, 6]; arr.slice(0, 3); // output = [1, 2, 3], arr = [1, 2, 3, 4, 5, 6] arr.slice(0, 3); // output = [1, 2, 3], arr = [1, 2, 3, 4, 5, 6] // splice: not Pure Function const arr = [1, 2, 3, 4, 5, 6]; arr.splice(0, 3); // output = [1, 2, 3], arr = [4, 5, 6] arr.splice(0, 3); // output = [4, 5, 6], arr = [] ``` <h5>溫馨小提示 : arr.splice(要插入或刪除的索引位置, 要刪除的元素數量, 要插入的元素內容) arr.slice( begin(起始為 0)從index開始提取拷貝 , end索引值之前停止提取 )</h5> <h4>3. Declarative vs Imperative (宣告式編程)</h4> * Declarative Paradigm (宣告式編程)一 較為抽象的程式碼,可以藉由自然語言直觀的理解該行程式碼想要達到什麼樣的結果。描述該在哪做什麼(what to do)以及資料流程(data flow)。 然而宣告式編程較依賴表達式(expression),表達式是一個單純的運算過程,並且總是會返回值。屬於宣告式編程的程式語言有,HTML、SQL、LINQ。 * Imperative Paradigm (指令式編程) 一 程式碼具體表達需要做什麼來達到目標。描述該做什麼(how to do)以及流程控制(flow control)。 而指令式編程的程式碼經常使用程式語言基本的語句(statement),例如:for, while, if , switch…等等。屬於指令式編程的程式語言有,C、JAVA。 Code example : ``` const a = [1, 2, 3, 4, 5]; // Declarative Programming declarativeSquare = (arr) => arr.map((val) => val*val) declarativeSquare(a); // [1, 4, 9, 16, 25] // Imperative Programming imperativeSquare = (arr) => { for (var i = 0; i < arr.length; i++) { arr[i] *= arr[i]; } return arr; } imperativeSquare(a); // [1, 4, 9, 16, 25] ``` <h3>Source:</h3> Functional Programming 是什麼:https://ithelp.ithome.com.tw/articles/10233399 Functional Programming 的使用:https://totoroliu.medium.com/javascript-functional-programming-%E5%87%BD%E5%BC%8F%E7%B7%A8%E7%A8%8B%E6%A6%82%E5%BF%B5-e8f4e778fc08 splice:https://ithelp.ithome.com.tw/articles/10225345 slice:https://ithelp.ithome.com.tw/articles/10224915