本文目錄一覽:
- 1、js函數式編程思想就是運算不改變值只是新建值嗎?
- 2、函數式編程 vs 面向對象編程 vs 過程式編程的JS演示比較
- 3、前端必學-函數式編程(六)
- 4、JS編程是什麼意思?
- 5、js 什麼是函數式編程
- 6、JS函數式編程和遞歸探索:路由樹的操作
js函數式編程思想就是運算不改變值只是新建值嗎?
你好,你可以這樣理解,函數式編程它不修改狀態,因此函數式編程只是返回新的值,不修改系統變量。函數式編程思想是把運算過程盡量寫成一系列嵌套的函數調用。
它主要是通過閉包和高階函數等來進行編程,屬於面向過程編程,強調通過函數,而不是語句來編程。
函數式編程 vs 面向對象編程 vs 過程式編程的JS演示比較
這是一個真實的例子,展示了三種最常見的編程範式的差異。我將用三種不同的方式解決一個問題。
每個示例將處理表單提交、驗證用戶輸入並將創建的用戶打印到控制台。我還添加了保存錯誤記錄器。
案例表單
簡單的 HTML 登錄表單,它將包含三個js不同範式的有效文件。
過程化編程
過程式編程只是一步一步地解決問題。這是完全有效的編碼方式,但是當您希望應用程序擴展時它有許多缺點。
簡單一步一步解決問題。但它根本不可重用和可擴展。儘管它對於解決此類問題完全有效,並且您將看到它比其他問題要短得多。
面向對象編程
面向對象編程 ( OOP ) 是最接近現實世界的,因此很容易讓您思考。我們查看將其劃分為Object的代碼,其中每個都只完成它的工作。在OOP 中學習的有用概念是SOLID。
現在你可以明白我將問題劃分為Objects 的意思了:
正如你所看到的,有更多的代碼,看起來更複雜……那麼為什麼有人會喜歡這個?
酷的是,現在我們可以將它用於任何類似的形式,只需調用:
因此,它可以在包含此腳本的每個文件中重複使用。而且它很容易擴展,因為一切都被分成只做一件事的塊(單一責任原則)。
函數式編程
非常流行,而且非常簡單。請注意,這並不意味着它無論如何都更好。儘管某些範例可能對某些問題更好,但使用哪個完全取決於您。
正如您在 函數式編程 中看到的,我們希望使用小的(理想情況下是純函數)函數來解決問題。這種方法也非常具有可 擴展性 ,並且函數可以重用。
純函數是一種沒有難以追蹤的副作用的函數。純函數應該只依賴於給定的參數。
結論
沒有更好和更壞的範式。有經驗的開發人員可以看到每個的優點,並為給定的問題選擇最好的。
過程式編程並不是說你不能使用函數,函數式編程也不會阻止你使用「類」。這些範式只是幫助以一種隨着代碼增長而有益的方式來解決問題。
函數式編程 vs 面向對象編程 vs 過程式編程的JS演示比較 – DEV
前端必學-函數式編程(六)
我們前篇談了很多關於【閉包】的理解了,所以你應該會知道,我們現在將要談的就是 ——【異步】。
我們為什麼覺得「異步問題」複雜呢?
其中很重要的一個原因是 —— 時間!時間將我們對數據的操作、管理,變複雜了好幾個量級!
(需要特別提出並明確的是: 異步和同步之間是可以相互轉化的! 我們使用異步或者同步取決於 —— 如何使代碼更加可讀!)
函數式編程給出了實現「代碼更可讀」的落地原則(已多次回顧):
所以我們可以期待,異步在函數式編程中的表現!
上代碼:
onCustomer(..) 和 onOrders(..) 是兩個【回調函數】釋義,兩者執行的先後順序並不能確定,所以它是一個基於時間的複雜狀態。
釋義:回調函數其實就是一個參數,將這個函數作為參數傳到另一個函數裏面,當那個函數執行完之後,再執行傳進去的這個函數。
通常來說,我們最先想到的是:把 lookupOrders(..) 寫到 onCustomer(..) 裏面,那我們就可以確認 onOrders(..) 會在 onCustomer(..) 之後運行。
這樣寫,對嗎?
不對!因為 onCustomer(..) 、 onOrders(..) 這兩個回調函數的關係更像是一種競爭關係(都是賦值 customer.orders ), 它們應該並行執行 , 而不是串行執行 。
即:我不管你們誰先執行,誰先執行完,誰就賦值給 customer.orders !
那我們的思路應該是:
不過,這樣讓代碼又變得更加難閱讀!!函數內部賦值依賴於外部變量、甚至受外部回調函數的影響。
那究竟怎麼辦呢?
最終,我們借用 JS promise 減少這個時間狀態,將異步轉成同步:
兩個 .then(..) 運行之前, lookupCustomer(..) 和 lookupOrders(..) 已被同步調用,滿足並行執行,誰先結束,誰賦值給 customer.orders ,所以我們不需要知道誰先誰後!
在這樣的實現下,不再需要時間先後的概念!減少了時間狀態!!代碼的可讀性更高了!!
這是一個 積極的數組 ,因為它們同步(即時)地操作着離散的即時值或值的列表/結構上的值。
什麼意思?
a 映射到 b,再去修改 a ,b 不會收到影響。
而這,是一個 惰性的數組 , mapLazy(..) 本質上 「監聽」 了數組 a,只要一個新的值添加到數組的末端(push(..)),它都會運行映射函數 v = v * 2 並把改變後的值添加到數組 b 里。
什麼意思?
a 映射到 b,再去修改 a ,b 也會修改。
原來,後者存在 異步 的概念。
讓我們來想像這樣一個數組,它不只是簡單地獲得值,它還是一個懶惰地接受和響應(也就是「反應」)值的數組,比如:
設置「懶惰的數組」 a 的過程是異步的!
b ,是 map 映射後的數組,但更重要的是,b 是 反應性 的,我們對 b 加了一個類似監聽器的東西。
這裡直接給出解答:
這裡再多小結一句:時間讓異步更加複雜,函數式編程在異步下的運用就是減少或直接幹掉時間狀態。
想像下 a 還可以被綁定上一些其他的事件上,比如說用戶的鼠標點擊事件和鍵盤按鍵事件,服務端來的 websocket 消息等。
上述的 LazyArray 又可叫做 observable !(當然,它不止用在 map 方法中)
現在已經有各種各樣的 Observables 的庫類,最出名的是 RxJS 和 Most 。
以 RxJS 為例:
不僅如此,RxJS 還定義了超過 100 個可以在有新值添加時才觸發的方法。就像數組一樣。每個 Observable 的方法都會返回一個新的 Observable,意味着他們是鏈式的。如果一個方法被調用,則它的返回值應該由輸入的 Observable 去返回,然後觸發到輸出的 Observable里,否則拋棄。
比如:
本篇介紹了【異步】在函數式編程中的表現。
原則是:對於那些異步中有時態的操作,基礎的函數式編程原理就是將它們變為無時態的應用。即 減少時間狀態 !
就像 promise 創建了一個單一的未來值,我們可以創建一個積極的列表的值來代替像惰性的observable(事件)流的值。
我們介紹了 RxJS 庫,後續我們還會介紹更多優美的 JS 函數式編程庫!
(俗話說的好,三方庫選的好,下班都很早!!)
現在本瓜有點明白那句話了:看一門語言是不是函數式編程,取決於它的核心庫是不是函數式編程。
也許我們還不熟悉像 RxJS 這類庫,但我們慢慢就會越來越重視它們,越來越使用它們,越來越領會到它們!!
異步,以上。
JS編程是什麼意思?
計算機專業語言。
簡單來說,就是編寫編定程序,讓計算機代碼解決某個問題,對某個計算體系規定一定的運算方式,使計算體系按照該計算方式運行,並最終得到相應結果的過程。
為了使計算機能夠理解人的想法,人類通過某種方式,將需解決的問題的思路、方法和手段通過計算機能夠理解的形式告訴它,讓計算機完成人的指令。
js 什麼是函數式編程
寫一個函數(即方法:function),然後去調用這個方法、比如寫個C的helloworld然後調用printf就是函數式(過程化)編程,
補充:JavaScript一種直譯式腳本語言,是一種動態類型、弱類型、基於原型的語言,內置支持類型。它的解釋器被稱為JavaScript引擎,為瀏覽器的一部分,廣泛用於客戶端的腳本語言,最早是在HTML(標準通用標記語言下的一個應用)網頁上使用,用來給HTML網頁增加動態功能。
在1995年時,由Netscape公司的Brendan Eich,在網景導航者瀏覽器上首次設計實現而成。因為Netscape與Sun合作,Netscape管理層希望它外觀看起來像Java,因此取名為JavaScript。但實際上它的語法風格與Self及Scheme較為接近。
JS函數式編程和遞歸探索:路由樹的操作
開始切入正題之前,有必要告知大家一下,這篇文章可能有一些深度,初學者可能理解會有些吃力。我會盡量把複雜問題簡單化,爭取讓每個閱讀的童鞋們都能看得懂。希望你對element-ui,vue-router,KeepAlive組件有一點了解。現在,我們開始吧。
熟悉element-ui的童鞋們都知道,ElMenuItem和ElSubMenu都需要一個index屬性,該屬性必須是唯一的。現在,我們想把路由配置直接應用於ElMenu,該如何確保index的唯一性呢?我們需要有一個生成唯一index的函數。如下是genKey函數的定義,是不是很簡單?
現在,我們創建addRouteMetaKey函數,該函數對路由樹進行遞歸遍歷,為每一個路由配置的meta屬性動態添加key字段。這個函數很簡單,屬於最基礎的遞歸使用例子,我就不做太多解釋了。
提示 :數組的forEach方法不是純函數,因為它有副作用,所以forEach方法不能稱之為函數式編程工具。
通過addRouteMetaKey函數,我們可以把路由的meta.key作為index的值了。
現在,我們想實現另一個功能,就是 基於標籤頁的路由組件緩存控制 。使用過Vuejs KeepAlive組件的童鞋們,應該多多少少都遇到一些坑吧?在我們的項目中,有一個頂部標籤頁導航,每個tab項對應一個url,以每個url對應路由的title作為tab項標題,當切換tab的時候加載緩存中的url對應的路由組件,關閉tab項,下次打開該路由url,重新掛載對應的路由組件,而不是從緩存中加載。
當路由層級不確定的時候,KeepAlive會變的難以手動控制。所以,我 劍走偏鋒,嘗試了一種簡單的解決方案 ,實踐證明: 這是非常有效的 。我的方案就是把無限層級的路由樹轉化為一維數組。通過為meta添加必要的字段,進行頁面結構個性化定製。
我們需要把每層路由配置的path轉化為全路徑,所以需要一個函數:getRouteFullPath,該函數定義如下:
getRouteFullPath函數中使用到的joinPath函數用於將多個路徑字符串拼接為1個完整的路徑,定義如下:
現在,我們把路由樹轉化為一維數組。我們定義toFlatRoutes函數,該函數使用了數組的reduce方法對路由樹進行聚合遞歸,將路由配置中的path屬性的值替換為全路徑,還順便給路由配置添加了name屬性,返回一個新的一維路由配置數組。 這是函數式編程和遞歸結合的一個例子。
以上,我們解決了KeepAlive的緩存控制問題;現在,我們又有了一個新的用戶體驗上的需求,就是我們想根據url對應的路由,自動展開該路由meta.key所屬的側邊菜單;我們通過查閱element-ui文檔得知,ElMenu有一個open方法,接收index作為參數,展開index對應的菜單。
現在的問題是,我們的路由對應的index是ElMenuItem的,而路由樹已經被我們轉化為了一維數組,通過路由的matched字段是得不到我們想要的菜單index的。所以, 我們需要遍歷原始路由樹 。
如下代碼,我們定義getMenuKey函數,該函數接收的參數為route對象。如果路由存在,我們進行查找。首先進行簡單查找,如果找到一個菜單menu,則返回該菜單的meta.key;如果簡單查找無果,則對路由樹進行遞歸查找; 這是函數式編程和遞歸結合的另一個例子。
現在,我們大功告成了;以上就是本節的知識點,童鞋們理解了嗎?只要我們熟悉遞歸的使用,其實操作樹很簡單。如果大家還有不懂的,可以評論區問我。感謝閱讀!
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/199315.html