摘要:函數(shù)是一等公民。其實閉包本身也是函數(shù)式編程的一個應(yīng)用。劣勢不能算是嚴格意義上的函數(shù)式語言,很多函數(shù)式編程的特性并沒有。
隨著大前端時代的到來,在產(chǎn)品開發(fā)過程中,前端所占業(yè)務(wù)比重越來越大、交互越來越重。傳統(tǒng)的老夫拿起JQuery就是一把梭應(yīng)付當下重交互頁面已經(jīng)十分乏力。于是乎有了Angular,React,Vue這些現(xiàn)代框架。
但隨之而來的還有大量的新知識新名詞,如MVC,MVVM,F(xiàn)lux這些設(shè)計模式就弄得很多同學(xué)傻傻分不清。這時候又見到別人討論什么函數(shù)式編程,更是一臉懵逼了。
我們大多聽過面向?qū)ο缶幊蹋嫦蜻^程編程,那啥又是函數(shù)式編程呢?在我們前端開發(fā)中又有哪些應(yīng)用場景?我抱著這個疑惑,初步的學(xué)習(xí)了下。(此文僅是學(xué)習(xí),無甚干貨)。
函數(shù)式編程 定義函數(shù)式編程(Functional Programming,后面簡稱FP),維基百科的定義是:
是一種編程范型,它將電腦運算視為數(shù)學(xué)上的函數(shù)計算,并且避免使用程序狀態(tài)以及易變對象。函數(shù)編程語言最重要的基礎(chǔ)是λ演算(lambda calculus)。而且λ演算的函數(shù)可以接受函數(shù)當作輸入(引數(shù))和輸出(傳出值)。比起命令式編程,函數(shù)式編程更加強調(diào)程序執(zhí)行的結(jié)果而非執(zhí)行的過程,倡導(dǎo)利用若干簡單的執(zhí)行單元讓計算結(jié)果不斷漸進,逐層推導(dǎo)復(fù)雜的運算,而不是設(shè)計一個復(fù)雜的執(zhí)行過程。
我來嘗試理解下這個定義,好像就是說,在敲代碼的時候,我要把過程邏輯寫成函數(shù),定義好輸入?yún)?shù),只關(guān)心它的輸出結(jié)果。而且可以把函數(shù)作為輸入輸出。感覺好像平常寫js時,就是這樣的嘛!
特性網(wǎng)上FP的定義與特性琳瑯滿目。各種百科、博客、一些老師的網(wǎng)站上都有大同小異的介紹。為了方便閱讀,我列下幾個好像比較重要的特性,并附上我的第一眼理解。
函數(shù)是一等公民。就是說函數(shù)可以跟其他變量一樣,可以作為其他函數(shù)的輸入輸出。喔,回調(diào)函數(shù)就是典型應(yīng)用。
不可變量。就是說,不能用var跟let咯。按這要求,我似乎有點難寫代碼。
純函數(shù)。就是沒有副作用的函數(shù)。這個好理解,就是不修改函數(shù)外部的變量。
引用透明。這個也好理解,就是說同樣的輸入,必定是同樣的輸出。函數(shù)內(nèi)部不依賴外部狀態(tài),如一些全局變量。
惰性計算。大意就是:一個表達式綁定的變量,不是聲明的時候就計算出來,而是真正用到它的時候才去計算。
還有一些衍生的特性,如柯里化與組合,三言兩語說不清,就不闡述了,有興趣的同學(xué)可以自己再了解了解。
FP在JavaScript中的應(yīng)用React就是典型的FP。它不同于Vue這樣的MVVM框架,它僅僅是個View層。
ReactView = render(data) 它只關(guān)心你的輸入,最終給你返回相應(yīng)視圖。所以你休想在react組件中去修改父組件的狀態(tài),更沒有與dom的雙向綁定。
這個是框架上的應(yīng)用,那么在我們平常書寫JavaScript時有哪些應(yīng)用呢?換句話說,平常書寫js時候,遇到什么情況,我們采用FP會更好。
從最常見的入手吧,如典型的操作數(shù)組:
// 從users中篩選出年齡大于15歲的人的名字 const users = [ { age: 10, name: "張三", }, { age: 20, name: "李四" }, { age: 30, name: "王五" } ]; // 過程式 const names = []; for (let i = 0; i < users.length; i++) { if (users[i].age > 15) { names.push(users[i].name); } } // 函數(shù)式 const names = users.filter(u => u.age > 15).map(u => u.name);
嗯,代碼精簡了很多,但是貌似帶來了更大的開銷。如果是非常大的數(shù)據(jù),非常多的篩選工作,那就會循環(huán)多次。
這里得想到剛剛的惰性計算。按照惰性求值的要求,應(yīng)該是要最后返回結(jié)果時,才真正去篩選年紀并得到姓名數(shù)組。
然而JavaScript的數(shù)組并不支持惰性求值。這時候我們得上一些工具庫,如Lodash。可以看下它文檔中的例子:_.chain。
好像也沒好到哪里去啊,不就是把多行代碼變一行嘛?說的那么玄乎,還多了性能開銷,然后又跟我說得上個工具庫。。。
說的好像很有道理,但是for循環(huán)是有個弊端的,它產(chǎn)生了變量i,而這個變量又是不可控的,如果業(yè)務(wù)邏輯一復(fù)雜,誰知道它循環(huán)到什么時候i有沒有發(fā)生變化,然后導(dǎo)致循環(huán)出問題呢?
我們再看一個與DOM交互的場景:
假如頁面有一個按鈕button,我們需要求出用戶點擊了幾次,但是一秒鐘內(nèi)重復(fù)點擊的不算。傳統(tǒng)方法會這么寫。
var count = 0; var rate = 1000; var lastClick = Date.now() - rate; var button = document.querySelector("button"); button.addEventListener("click", () => { if (Date.now() - lastClick >= rate) { console.log(`Clicked ${++count} times`); lastClick = Date.now(); } });
妥,完全沒問題。但是發(fā)現(xiàn)多了很多狀態(tài),count,rate,lastClick,還得對比來對比去。那如果用FP會是怎么樣的呢?
抱歉。。。沒法寫。。。除非很強大的編程能力,自己封裝好方法去處理。所以在這里,我們可以上個工具---Rx.js,上述的例子就是rxjs中引用的,我們看它是如何優(yōu)雅地處理的。
var button = document.querySelector("button"); Rx.Observable.fromEvent(button, "click") .throttleTime(1000) // 每隔1000毫秒才能觸發(fā)事件 .scan(count => count + 1, 0) // 求值,默認值是0 .subscribe(count => console.log(`Clicked ${count} times`)); // 訂閱結(jié)果、輸出值
巧奪天工!再也不用去管理狀態(tài)了,不需要聲明一堆變量,修改來修改去,判斷來判斷去,簡直完美。
平常我們有很多需要更新dom的異步操作,如搜索行為:用戶連續(xù)輸入查詢值,如果停頓半秒就執(zhí)行搜索,如果搜索了多次,發(fā)起了多次請求,那只返回最終輸入的那次搜索結(jié)果。
閉上眼想想,你之前是怎么實現(xiàn)的。反正我都是設(shè)置開始時間,結(jié)束時間,上次時間,等等變量。繁瑣,而且不可控。
當我們以FP的思想去實現(xiàn)時,就會想方設(shè)法的減少變量,來優(yōu)雅程序。最常見的方法就是用下別人的工具庫來實現(xiàn)它。當然有些簡單的場景也可以自己實現(xiàn),最主要的還是要有這個意識。
其實我們平常已經(jīng)寫了一些FP了,只是我們沒意識到,或者沒怎么寫好。就好比閉包,很多人都不了解閉包的概念,但實際上已經(jīng)寫了很多閉包代碼。其實閉包本身也是函數(shù)式編程的一個應(yīng)用。
鑒于我自己理解也不深,沒法多闡述FP的應(yīng)用,大家如果有興趣,可以多了解了解。
FP在JavaScript中的優(yōu)劣勢總結(jié)一下FP的優(yōu)劣,以便于我們在實際開發(fā)中,能更好的抉擇是否采用FP。
優(yōu)勢更好的管理狀態(tài)。因為它的宗旨是無狀態(tài),或者說更少的狀態(tài)。而平常DOM的開發(fā)中,因為DOM的視覺呈現(xiàn)依托于狀態(tài)變化,所以不可避免的產(chǎn)生了非常多的狀態(tài),而且不同組件可能還相互依賴。以FP來編程,能最大化的減少這些未知、優(yōu)化代碼、減少出錯情況。
更簡單的復(fù)用。極端的FP代碼應(yīng)該是每一行代碼都是一個函數(shù),當然我們不需要這么極端。我們盡量的把過程邏輯以更純的函數(shù)來實現(xiàn),固定輸入->固定輸出,沒有其他外部變量影響,并且無副作用。這樣代碼復(fù)用時,完全不需要考慮它的內(nèi)部實現(xiàn)和外部影響。
更優(yōu)雅的組合。往大的說,網(wǎng)頁是由各個組件組成的。往小的說,一個函數(shù)也可能是由多個小函數(shù)組成的。參考上面第二點,更強的復(fù)用性,帶來更強大的組合性。
隱性好處。減少代碼量,提高維護性。
劣勢JavaScript不能算是嚴格意義上的函數(shù)式語言,很多函數(shù)式編程的特性并沒有。比如上文說的數(shù)組的惰性鏈求值。為了實現(xiàn)它就得上工具庫,或者自己封裝實現(xiàn),提高了代碼編寫成本。
跟過程式相比,它并沒有提高性能。有些地方,如果強制用FP去寫,由于沒有中間變量,還可能會降低性能。
代碼不易讀。這個因人而異,因碼而已。特別熟悉FP的人可能會覺得這段代碼一目了然。而不熟悉的人,遇到寫的晦澀的代碼,看著一堆堆lambda演算跟匿名函數(shù) () => () => () 瞬間就懵逼了。看懂代碼,得腦子里先演算半小時。
學(xué)習(xí)成本高。一方面繼承于上一點。另一方面,很多前端coder,就是因為相對不喜歡一些底層的抽象的編程語言,才來踏入前端坑,你現(xiàn)在又讓他們一頭扎入FP,顯得手足無措。
總結(jié)個人覺得,F(xiàn)P還是好的。對于開發(fā)而言,確確實實能優(yōu)化我們的代碼,熟悉之后,也能提高編程效率。對于編程本身而言,也能拓展我們的思維,不局限在過程式的編程代碼。
在編寫JS中,可以盡量的運用FP的思維,如不可變量、純函數(shù)、惰性求值。但也不必教條式的遵循函數(shù)式編程,一定要怎樣怎樣。比如我們看下知乎大V某溫的一個回答:傳送門。
唉,做個頁面仔不容易啊。但是不想當大牛的頁面仔不是好頁面仔!
參考函數(shù)式編程入門教程-阮一峰
函數(shù)編程語言-維基百科
前端開發(fā)js函數(shù)式編程真實用途體現(xiàn)在哪里?-知乎答者
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/83560.html
摘要:函數(shù)是一等公民。其實閉包本身也是函數(shù)式編程的一個應(yīng)用。劣勢不能算是嚴格意義上的函數(shù)式語言,很多函數(shù)式編程的特性并沒有。 隨著大前端時代的到來,在產(chǎn)品開發(fā)過程中,前端所占業(yè)務(wù)比重越來越大、交互越來越重。傳統(tǒng)的老夫拿起JQuery就是一把梭應(yīng)付當下重交互頁面已經(jīng)十分乏力。于是乎有了Angular,React,Vue這些現(xiàn)代框架。 但隨之而來的還有大量的新知識新名詞,如MVC,MVVM,F(xiàn)l...
摘要:閉包,原型,原型鏈,繼承對象若干屬性的集合輸出的集中類型標識,其中上面的四種屬于簡單的值類型,不是對象。在實際應(yīng)用中如何區(qū)分一個屬性到底是基本的還是從原型中找到的呢,特別是在循環(huán)中由于所有的對象的原型鏈都會找到,因此所有的對象都會有的方法。 閉包,原型,原型鏈,繼承 對象——若干屬性的集合 typeof輸出的集中類型標識,其中上面的四種(undefined, number, strin...
摘要:前端日報精選新的長度單位你知道么高階函數(shù)一點通的故事隔行掃描算法專題之數(shù)組去重全家桶每個人都能做的網(wǎng)易云音樂騰訊前端團隊社區(qū)中文前端推薦第天聽說你缺少一個順手的圖床知乎專欄譯怎樣創(chuàng)建定制表單組件碎語掘金函數(shù)式編程到底是個啥 2017-06-22 前端日報 精選 CSS 新的長度單位 fr 你知道么?高階函數(shù)一點通png的故事:隔行掃描算法JavaScript專題之數(shù)組去重 · Issu...
摘要:由于函數(shù)被調(diào)用了,線程會從剛剛保存的變量中取出內(nèi)容,去解析執(zhí)行它。最后,當線程遇到離開上下文的標識,便離開上下文,并把的結(jié)果一并返回出去。 原文鏈接,歡迎關(guān)注我的博客 我相信很多前端初學(xué)者一開始都會被執(zhí)行上下文這個概念弄暈,或者說似懂非懂。對于工作兩年的我來說,說來實在慚愧,雖然知道它大概是什么,但總覺得沒有一個更為清晰的認識(無法把它的工作過程描述清楚),因此最近特意溫習(xí)了一遍,寫下...
摘要:理解的函數(shù)基礎(chǔ)要搞好深入淺出原型使用原型模型,雖然這經(jīng)常被當作缺點提及,但是只要善于運用,其實基于原型的繼承模型比傳統(tǒng)的類繼承還要強大。中文指南基本操作指南二繼續(xù)熟悉的幾對方法,包括,,。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。 怎樣使用 this 因為本人屬于偽前端,因此文中只看懂了 8 成左右,希望能夠給大家?guī)韼椭?...(據(jù)說是阿里的前端妹子寫的) this 的值到底...
閱讀 2556·2021-11-22 12:05
閱讀 3441·2021-10-14 09:42
閱讀 1675·2021-07-28 00:15
閱讀 1982·2019-08-30 11:08
閱讀 1476·2019-08-29 17:31
閱讀 920·2019-08-29 16:42
閱讀 2329·2019-08-26 11:55
閱讀 2108·2019-08-26 11:49