一文帶你理解JavaScript中的函數(shù)式編程
我理解的 函數(shù)式編程 是一種 編程規(guī)范,也是一種對語言程序(比如JavaScript)本身能力的 運(yùn)用方式。
就 編程規(guī)范 來說,對開發(fā)者來說可以說是一種約束,但在這種約束下,會讓我們編寫出更加可控且穩(wěn)定的程序。
就 運(yùn)用方式 來說,函數(shù)式編程本身有很多經(jīng)典的運(yùn)用方式,對于 JavaScript 語言本身而言,天然支持了 函數(shù)式編程,因此,我們可以直接它的一些運(yùn)用方式,來擴(kuò)展我們的語言運(yùn)用能力。
本篇文章將從 編程規(guī)范 來介紹函數(shù)式編程的到底是一種什么樣的規(guī)范,它能帶給我們作用有什么。
分析
函數(shù)式編程核心規(guī)范就是:擁抱 純函數(shù) ,隔離 副作用 。
因此要弄清楚 函數(shù)式編程 的規(guī)范,就需要弄懂 純函數(shù) 和 副作用 概念和作用。
我們先來看一下各自的概念:
純函數(shù):就是一個函數(shù),但它需要滿足以下兩個特征:
- 相同的輸入?yún)?shù),總會有相同的輸出
- 在執(zhí)行過程中不會產(chǎn)生語義上可觀察的 副作用
副作用:函數(shù) 副作用 指當(dāng)調(diào)用函數(shù)時,除了返回函數(shù)值之外,還對主調(diào)用函數(shù)產(chǎn)生附加的影響。
純函數(shù)的理解依賴 副作用,因此不會分開去理解,本篇具體內(nèi)容結(jié)構(gòu):
- 理解純函數(shù)
- 純函數(shù)的作用
- 如何對待副作用
理解純函數(shù)
下面我們從 純函數(shù) 的兩個特征來理解。
相同的輸入?yún)?shù),總會有相同的輸出
比如:
function add(a, b) { return a + b } add(1, 2); // 3
執(zhí)行 add
函數(shù),不管執(zhí)行多少次,不管在 JavaScript 上下文哪里執(zhí)行,相同的參數(shù)傳遞進(jìn)去后,總會返回相同的輸出,且不會對外界造成影響,是一個 純函數(shù) 。
如果改成這樣:
let c = 1; function add(a, b) { return a + b + c; } add(1, 2); // 4 c = 5; add(1, 2); // 8
這時候 add
調(diào)用了兩次,傳遞進(jìn)去的參數(shù)沒有變化,但返回結(jié)果卻不相同,它受到了外界變量的干擾,不屬于純函數(shù)。
因此,可以推斷出要想 相同的輸入?yún)?shù),總會有相同的輸出 ,函數(shù)內(nèi)部不能使用函數(shù)外部的 變量 ,但不可變的 常量 是可以的,比如在使用 redux時,定義 reducer 的 action 常常就會使用常量來定義。
相同的輸入?yún)?shù),總會有相同的輸出 可以保證我們程序的穩(wěn)定性,返回結(jié)果不受外界影響。
在執(zhí)行過程中不會產(chǎn)生語義上可觀察的 副作用
比如:
function add(a, b) { const result = a + b; console.log(result); return result; } add(1, 2); // 3
上面的 add
函數(shù)添加了 console.log
把結(jié)果打印到了瀏覽器的控制臺,屬于對外界造成了影響,產(chǎn)生了 副作用
。
再比如一個請求接口的函數(shù):
async function getList(url) { const result = await fetch(url); return result; }
內(nèi)部調(diào)用了請求函數(shù) fetch
,fetch
函數(shù)執(zhí)行后返回的內(nèi)容并不能保證每一次都一樣,受到了網(wǎng)絡(luò)和服務(wù)器等原因的影響。因此,fetch
函數(shù)本身就不是一個純函數(shù),getList
受到其影響,也變得不純了。
因此,如果一個主函數(shù)內(nèi)部調(diào)用了不純函數(shù),不純的原因還是對主函數(shù)外部產(chǎn)生了副作用或者收到了影響,那么這個函數(shù)就不是純函數(shù)。
純函數(shù) 的作用
純函數(shù) 的兩大特征,合起來可以這樣看:不受外界影響,不影響外界。也就是它可以解決程序中 不確定性 的問題。
不確定性的危害
以測試過程為例:單元測試的主要判斷的依據(jù)就是函數(shù)的輸入和輸出。如果對于同樣的輸入,函數(shù)不能夠給到確定的輸出,那就很難進(jìn)行測試了。
不確定性還會導(dǎo)致我們的程序中出現(xiàn)各種風(fēng)險(xiǎn),比如:
- 代碼難以被調(diào)試
- 數(shù)據(jù)變化難以被追溯
- 計(jì)算結(jié)果難以被復(fù)用(代碼難以封裝)
- 程序運(yùn)行中容易出現(xiàn)各種突發(fā)性的事件
確定性的好處
確定性的函數(shù)讓我們的程序更加有保障,也能解決很多實(shí)際性的問題,比如:
- 代碼邏輯更加清晰。
- 更容易進(jìn)行測試,結(jié)果只依賴輸入,測試時可以確保輸出穩(wěn)定。
- 更容易維護(hù)和重構(gòu),我們可以寫出質(zhì)量更高的代碼。
- 更容易調(diào)用,我們不用擔(dān)心函數(shù)會有什么副作用。
- 結(jié)果可以緩存,因?yàn)橄嗤妮斎肟偸菚玫较嗤妮敵觥?/li>
- 代碼復(fù)用性強(qiáng),提升開發(fā)者的編碼效率。
如何對待副作用
解決 副作用 等于解決了影響外界的問題和部分不受外界影響的問題。因此消除副作用,足以解決函數(shù)中大多數(shù)的不確定性問題。
但對于一個完整的程序來說,副作用卻至關(guān)重要,沒有副作用,程序就不能和外界溝通,就不能產(chǎn)生對外界的作用,這樣程序本身就沒有了意義和價(jià)值。
因此我們要做的不是消除副作用,而是擁抱 純函數(shù) ,隔離 副作用 。將計(jì)算邏輯與副作用做合理的分層解耦,從而提升我們的編碼質(zhì)量和執(zhí)行效率。
總結(jié)
函數(shù)式編程帶來了一種編程規(guī)范,而核心就是擁抱 純函數(shù),讓我們更加注重代碼本身的質(zhì)量和運(yùn)用能力。
到此這篇關(guān)于一文帶你理解JavaScript中的函數(shù)式編程的文章就介紹到這了,更多相關(guān)JavaScript函數(shù)式編程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
6行代碼實(shí)現(xiàn)微信小程序頁面返回頂部效果
這篇文章主要為大家詳細(xì)介紹了6行代碼實(shí)現(xiàn)微信小程序頁面返回頂部效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12js實(shí)現(xiàn)for循環(huán)跳過undefined值示例
這篇文章主要介紹了js實(shí)現(xiàn)for循環(huán)跳過undefined值,結(jié)合實(shí)例形式分析了js使用for循環(huán)針對數(shù)組的遍歷、判斷、運(yùn)算等相關(guān)操作技巧,需要的朋友可以參考下2019-07-07原生JS實(shí)現(xiàn)頂部導(dǎo)航欄顯示按鈕+搜索框功能
這篇文章主要介紹了原生js實(shí)現(xiàn)頂部導(dǎo)航欄顯示按鈕+搜索框功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-12-12純js和css實(shí)現(xiàn)漸變色包括靜態(tài)漸變和動態(tài)漸變
用javascript實(shí)現(xiàn)一下所謂的動態(tài)漸變,考慮動態(tài)原因就不上圖了,我來簡單介紹下思路2014-05-05一文詳解preact的高性能狀態(tài)管理Signals
這篇文章主要介紹了一文詳解preact的高性能狀態(tài)管理Signals,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的朋友可以參考一下2022-09-09JS結(jié)合WebSocket實(shí)現(xiàn)實(shí)時雙向通信
WebSocket 是一種在 Web 應(yīng)用程序中實(shí)現(xiàn)實(shí)時、雙向通信的協(xié)議,在本文中,我們將深入介紹 WebSocket 的原理、用法以及一些實(shí)際應(yīng)用場景,x需要的可以參考下2023-11-11