現代的JS有許多概念或者說一些編程技巧,這些概念有來自于其他語言、一些設計模式或者js語言特有的概念等,下面就來說一下與函式式編程密切相關的兩個概念:純函式和副作用
副作用
在計算機科學中,函式副作用指當呼叫函式時,除了回傳函式值之外,還對主呼叫函式產生附加的影響,例如修改全域變數(函式外的變數)或修改引數, --- 維基百科
例如在javascript的內置的一些函式是有副作用的:
[1, 2, 3].pop() // 每次執行pop函式,原陣列都會減少一個元素 [1, 2, 3].splice(1, 1) // 會洗掉原陣列里面的元素 ...
除了這些內置的函式會存在副作用,我們平時寫的一些操作Dom、修改登錄資訊和彈出一個彈窗等,這些例子都太多了,
無副作用 & 純函式
- 函式與外界的只有唯一一個渠道進行溝通,通過傳入引數和回傳值進行溝通,
- 相同的傳入引數永遠只會有相同的回傳值,
最簡單的例子:
function sum(a, b) { return a + b }
這兩個概念是相當簡單的,我們接下來看一下,函式式的出現給JS帶來了什么,解決了什么樣的問題,存在哪些問題,
帶來了什么
純函式函式式有一些優點:
- 可快取性(Cacheable)
- 可移植性/自檔案化(Portable / Self-Documenting)
- 可測驗性(Testable)
- 合理性(Reasonable)
- 并行代碼(Parallel Code)
單從這些有點來看,確實是一些軟體工程上所提倡的幾個觀點,在足夠靈活的情況下還能保證穩定性,想想一些場景,當你使用第三方庫的函式,傳入了你的比較重要的一個物件,結果被修改了,導致了整個程式的錯了,關鍵是這樣的問題還不好定位到,
let importantObj = { a: 1 } someFunc(a) console.log(importantObj ) // ??? 不知道被修改成什么樣子了,,,埋下了坑
比如,React、lodash和Redux等就巧妙應用了js的函式式編程,使得暴露出來的介面十分穩定,介面結構清晰,但是這些還只是用到了函式式的方式和技巧,還并不是完全的函式范式,真正的函式范式的限制更加嚴格,但是我認為不能一味的去追求這些嚴格的理論,而是適合的才是最好的,其中的一些函式式編程模型,比如:閉包(Closure)、高階函式、柯里化(Currying)和組合(Composing)等,讓更多的框架借鑒和使用,函式式編程這些特性給前端帶來了更多的活力,
解決了什么樣的問題
函式式編程關心資料的映射,命令式編程關心解決問題的步驟,如今前端應用功能越來越多,用戶互動越來越多,所有需要處理的用戶資料也是越來越復雜,管理這些資料是現在大家比較關心的事情和尋求突破的事情,
函式范式來處理這些資料,就可以使得資料的每一次修改都可以變得可以追溯,可以很容易的定位到問題的所在,因為無副作用的特性,減少了影響原始資料噪音,使得每次修改資料都比較穩定,
存在哪些問題
相對于宣告式和命令式,函式式的編程是比較不容易理解的,有些介面的用法有時候可能不好理解,下面我參考一下《重新思考 Redux》(rematch 作者 Shawn McKay 寫的一篇干貨軟文)里面有些相關段落進行舉例,
以下內容來著精讀《重新思考 Redux》 博客,里面文章很有深度,推薦閱讀,簡化初始化redux 初始化代碼涉及的概念比較多,比如 compose thunk 等等,同時將 reducer、initialState、middlewares 這三個重要概念拆分成了函式方式呼叫,而不是更容易接受的配置方式:
const store = preloadedState => { return createStore( rootReducer, preloadedState, compose(applyMiddleware(thunk, api), DevTools.instrument()) ); };
如果換成配置方式,理解成本會降低不少:
const store = new Redux.Store({ instialState: {}, reducers: { count }, middlewares: [api, devTools] });
筆者注:redux 的初始化方式非常函式式,而下面的配置方式就更面向物件一些,相比之下,還是面向物件的方式更好理解,畢竟 store 是一個物件,instialState 也存在同樣問題,相比顯示申明,將 preloadedState 作為函式入參就比較抽象了,同時 redux 對初始 state 的賦值也比較隱蔽,createStore 時統一賦值比較別扭,因為 reducers 是分散的,如果在 reducers 中賦值,要利用 es 的默認引數特性,看起來更像業務思考,而不是 redux 提供的能力,
通過上面博客的,可以看到,函式式的一些代碼理解起來并不是那么容易,
因為函式式的處理方式,每次都是產生一個新的資料,所有相對來說,需要的記憶體和占的資源是較高的,
總結
經過上面的分析,我們可以看到函式式的一些模型早已在如今的前端各種庫實行開來,并且效果都還很不錯,了解函式式的這個概念可謂是非常有必要的,但是是否一定需要函式式需要多多考慮,還是記住只有適合的技術,
參考文章
- 我眼中的 JavaScript 函式式編程
- 精讀《重新思考 Redux》
- JavaScript 函式式編程(一)
原文鏈接: https://github.com/zachrey/zblog/issues/3
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/261400.html
標籤:其他
