# 函數式程式設計 假設我們要將下面一組數字進行排序: ```typescript= var input = [3, 2, 4, 1] ``` 很快地,我們可能就想出以下的程式碼來達成需求: ```typescript= function sortInput() { // 去掉奇數 for (let i = 0; i < input.length; ++i) { for (let j = 0; j < input.length - i - 1; ++j) { if (input[j] > input[j + 1]) { [input[j], input[j + 1]] = [input[j + 1], input[j]] } } } } ``` ```typescript= var input = [3, 2, 4, 1] sortInput() console.log(input) // [1, 2, 3, 4] ``` 很快地,你可能會發現這個方法沒辦法重複使用,因為你沒辦法排序其他數列: ```typescript= function sort(input) { // 去掉奇數 for (let i = 0; i < input.length; ++i) { for (let j = 0; j < input.length - i - 1; ++j) { if (input[j] > input[j + 1]) { [input[j], input[j + 1]] = [input[j + 1], input[j]] } } } return input } ``` ```typescript= var input = [3, 2, 4, 1] console.log(sort(input)) // [1, 2, 3, 4] console.log(sort([5, 8, 7, 6])) // [5, 6, 7, 8] ``` 假設,此時有一個排序,它是要降冪排序: ```typescript= function sortBy(comparator, input) { // 去掉奇數 for (let i = 0; i < input.length; ++i) { for (let j = 0; j < input.length - i - 1; ++j) { if (input[j] > input[j + 1]) { [input[j], input[j + 1]] = [input[j + 1], input[j]] } } } return input } ``` 此時,得到一個意外的答案,奇數的陣列竟然是空的: ```typescript= var input = [1, 2, 3, 4] console.log(getEvenNumbers2(input)) // [2, 4] console.log(getOddNumbers(input)) // [] ``` 原因是 `Array.prototype.splice`這類的函式帶有「副作用」,它會更改原始陣列,讓我們優化一下: ```typescript= function getEvenNumbers3(input) { // 先進行淺拷貝 input = input.slice() for (let i = input.length - 1; i >= 0; --i) if (input[i] % 2 === 1) input.splice(i, 1) return input } function getOddNumbers2(input) { // 先進行淺拷貝 input = input.slice() for (let i = input.length - 1; i >= 0; --i) if (input[i] % 2 === 0) input.splice(i, 1) return input } ``` 接著測試看看: ```typescript= var input = [1, 2, 3, 4] console.log(getEvenNumbers3(input)) // [2, 4] console.log(getOddNumbers2(input)) // [1, 3] ``` 一切正常,但你可能會問 `getEvenNumbers3` 好像與 `getOddNumbers2` 看起來差不多? ```typescript= function filter(predicate, input) { // 先進行淺拷貝 input = input.slice() for (let i = input.length - 1; i >= 0; --i) if (predicate(input[i]) === false) input.splice(i, 1) return input } ``` 抽取共有的邏輯之後,我們可以得到一個 `filter` 「高階函式」,接受一個斷言函式,用以判斷是否要保留各個元素: ```typescript= var input = [1, 2, 3, 4] const isOdd = n => n % 2 === 1 const isEven = n => n % 2 === 0 console.log(filter(isOdd, input)) // [1, 3] console.log(filter(isEven, input)) // [2, 4] ``` 我們可以透過日常將這些函式抽取出來,來提升開發速度,也可以直接使用社群維護的函式庫,例如「Ramda」: ```typescript= import * as R from 'ramda' var input = [1, 2, 3, 4] const isOdd = n => n % 2 === 1 const isEven = n => n % 2 === 0 console.log(R.filter(isOdd, input)) // [1, 3] console.log(R.filter(isEven, input)) // [2, 4] ``` # 結論 - 提升開發速度 🚀 - 代碼可讀性高 - 降低專案體積 📦 - 避免邊夜問題 - 容易除錯追蹤 - 提升可測試性 - ...族繁不及備載
{"metaMigratedAt":"2023-06-15T01:17:39.276Z","metaMigratedFrom":"Content","title":"函數式程式設計","breaks":true,"contributors":"[{\"id\":\"e77f9ae0-feb2-4c38-9ae8-f06f8655e3a4\",\"add\":101404,\"del\":101416}]"}
    773 views