摘要:最近在看,順便看了一些函數式編程,然后半個國慶假期就沒有了。最開始接觸函數式編程的時候,第一個接觸的概念就是高階函數,和柯里化。所以我覺得最開始學習函數式編程最好先了解一些相關概念和思想會比較好。
最近在看Typescript,順便看了一些函數式編程,然后半個國慶假期就沒有了。做個筆記,分幾個部分寫吧。
最開始接觸函數式編程的時候,第一個接觸的概念就是高階函數,和柯里化。咋一看,這不就是長期用來講作用域的demo嗎?我在日常也有用啊,有啥嗎?
其實呢,設計模式或則編程范式往往不在于技巧,而在于思想。函數式編程就是一種編程的范式,并不在于技巧多么叼,而在于它的思想。其次才是由設計思想才衍生出來的技巧,技巧往往而言是服務于思想的。所以我覺得最開始學習函數式編程最好先了解一些相關概念和思想會比較好。
函數是一等公民(first class)如果理解直接看為一等公民的好處好處。
其實說函數式一等公民的意思就是說函數和其他“公民”具有相同的屬性。就像任何一種數據類型,它能夠被存儲在數組中,能夠作為函數的參數,能夠賦值給變量:
const hello = (name) => (`Hello ${name}!`) const sayHello = hello; // 作為變量 const helloArray = [hello, sayHello]
上面的代碼沒有什么意義,只是表達函數在JavaScript中是一等公民,和一個值一樣。
函數是一等公民的好處拿一個callback的例子來講,比如你用fetch發個請求時:
fetch("getPostLink") .then(res => renderPosts(res)) .catch(err => handleError(error))
上面其實可以直接傳遞一個函數作為回調,加一層包裹其實沒有必要:
fetch("getPostLink").then(renderPosts).catch(handleError)
多一層函數的包裹并沒有任何意義,完全是多余的代碼。再看一個例子:
const postController = { find(postId) { return Db.find(postId) }, delete(postId) { return Db.delete(postId) }, ... }
上面的代碼其實就是聚合一些功能作為一個對象,但是多加了一層的函數,也是沒有必要的,在閱讀的時候到會增加復雜度,其實postController.find === Db.find,所以完全沒有再去包裹一層函數:
const postController = { find: Db.find, delete: Db.delete, ... }
上面的代碼是不是更表意,然而如果js的函數不能像值一樣傳遞,上面的簡寫都是不可能的。上面的代碼其實還有一個好處,你不用去糾結如何命名在兩層函數之間的參數了。這種風格代碼是符合Pointfree的,我們后面要介紹。另外,函數式編程是操作函數的,所以函數是一等公民也是函數式的基石,基本上如果js不支持這一項,函數式根本玩不轉。
純函數讓我舉一個例子,大家在小學多學過一元一次方程吧:
f(x) = ax+b
這就是一個純函數,一個輸入然后返回一個輸出。所有的東西都是圍繞輸入的,一個輸入只可能返回一個輸出,然后對任何其他沒在作用域中的變量沒有任何操作。
更書面的解釋:一個純函數一個輸入永遠都只有一個同樣的輸出,然后不會產生任何副作用。副作用是啥我們一會兒再說。
不純的函數通常不純的函數分為兩類,一種是會改變輸入的:
const numbers = [1, 2, 3] // 純函數 numbers.slice(0, 3) // [1, 2, 3] numbers.slice(1, 3) // [2, 3] numbers.slice(0, 2) // [1, 2] // 不純的函數 numbers.splice(0, 3) // [1, 2, 3] numbers.splice(0, 3) // []
上面中在numbers這個數組上面的兩個方法,slice是純函數。而splice則不是純函數,它會改變輸入的數值。做了額外的事。
另外一種是對函數以外的狀態有依賴的:
let endpointForYoung = 18 // 不純的函數 const checkYoungPeople = age => age <= endpointForYoung // 純函數 const checkYoungPeople = age => { const endpointForYoung = 18 return age <= endpointForYoung }
像上面的函數,第一個就是不純的,他依賴的作用域之外的一個變量,一旦這個變量改變,這個函數返回的值就會跟著改變。
副作用副作用就是在函數計算過程中,對函數外的狀態進行更改或則與函數外狀態進行交互的行為。首先副作用會導致函數不純,是程序有不可控的依賴,不便于管理。但是,副作用是不可消除的,在正常的編程活動中是必然伴隨著副作用的。所以在面對副作用時,問題不是如何消除副作用,而是如何管理副作用。這個,會在我們講解范疇論相關概念的時候再深入。
正常編程活動中會引入的副作用有這些:
文件讀寫操作
增刪改查數據庫
http 請求
打印log
獲得用戶輸入
獲取dom元素
當然不限于上面這幾種,還有很多行為都帶有副作用。
純函數的好處能緩存
純函數的每次輸入和輸出都是沒有狀態的,所以結果都一樣,能夠被緩存在任何地方而不會造成錯誤。
可移植性,自文檔
// 不純函數 const signUp = (attrs) => { const user = saveUser(attrs); welcomeUser(user); }; // 純函數 const signUp = (Db, Email, attrs) => () => { const user = saveUser(Db, attrs); welcomeUser(Email, user); };
第二個signUp依賴是從上傳遞的,所以能直觀的看出saveUser需要Db,welcomeUser還需要Email。在不純的函數中你很難在調用的時候知道他的依賴,你需要查看代碼,才能搞清楚,“哦,原來還用了Db存了波數據啊。”
依賴作為參數傳入,也很容易的在移植到其他場景使用,畢竟函數只是功能,針對不同場景操作不同的數據。
易于測試
寫單測的時候,最麻煩的就是如何mock數據。通常有兩類數據最難mock,第一個是全局變量,比如document,另外一類是import進來的依賴,對于這兩種,雖然在一些測試套件中有現成的工具庫去mock。但是,都是很詭異的方式。
而如果是函數式的話,你測的就是一個輸入一個輸出,沒有外部的影響,是非常容易測試的。
并行代碼
純函數都是沒有狀態的,那即使跑在多臺機器多個進程,每個單元相互之間是沒有耦合關系的。
Pointfree大家可以看阮老師的這篇博客了解一下:http://www.ruanyifeng.com/blo...
我只扯一下Pointfree風格代碼的好處:
正如上面所說的中間變量沒有意義,不需要給變量命名
代碼更簡潔,精煉,不用將過多的狀態暴露給消費者
當然也有人認為其將太多的狀態隱藏了,初讀代碼很難理解,只有看了具體函數實現功能才能知道真正的意圖,對于代碼的可讀性而言,很糟糕。
這里有一處在hacker news上的討論Point-Free style: What is it good for?。另外這還有一篇具體使用場景的文章https://medium.freecodecamp.org/how-point-free-composition-will-make-you-a-better-functional-programmer-33dcb910303a。有興趣的小伙伴可以自己看看。
添加一張我筆記未整理的腦圖。
OK,下一篇介紹一下函數組合和柯里化。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/98227.html
摘要:我稱之為輕量級函數式編程。序眾所周知,我是一個函數式編程迷。函數式編程有很多種定義。本書是你開啟函數式編程旅途的絕佳起點。事實上,已經有很多從頭到尾正確的方式介紹函數式編程的書了。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson - 《You-Dont-Know-JS》作者 譯者團隊(排名不分先后):阿希、blueken、brucecham、...
摘要:本書主要探索函數式編程的核心思想。我們在中應用的僅僅是一套基本的函數式編程概念的子集。我稱之為輕量級函數式編程。通常來說,關于函數式編程的書籍都熱衷于拓展閱讀者的知識面,并企圖覆蓋更多的知識點。,本書統稱為函數式編程者。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson - 《You-Dont-Know-JS》作者 譯者團隊(排名不分先后)...
摘要:在學習的過程中時常會聽到一個名次函數式編程,那么究竟什么是函數式編程,函數式編程又有什么優點,這就在這篇博客進行一個簡單的總結吧主要內容函數式編程的概念函數式編程的優點與示例什么是函數式編程首先,我們放下編程的概念,我們來看函數。 在學習 JS 的過程中時常會聽到一個名次——函數式編程,那么究竟什么是函數式編程,函數式編程又有什么優點,這就在這篇博客進行一個簡單的總結吧~ 主要內容: 函...
摘要:為了盡可能提升互通性,已經成為函數式編程庫遵循的實際標準。與輕量級函數式編程的概念相反,它以火力全開的姿態進軍的函數式編程世界。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 關于譯者:這是一個流淌著滬江血液的純粹工程:認真,是 HTML 最堅實的梁柱;分享,是 CSS 里最閃耀的一瞥;總結,...
摘要:所以我覺得函數式編程領域更像學者的領域。函數式編程的原則是完善的,經過了深入的研究和審查,并且可以被驗證。函數式編程是編寫可讀代碼的最有效工具之一可能還有其他。我知道很多函數式編程編程者會認為形式主義本身有助于學習。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson - 《You-Dont-Know-JS》作者 關于譯者:這是一個流淌著滬江血液...
閱讀 1249·2023-04-26 02:38
閱讀 928·2023-04-25 20:13
閱讀 3589·2021-11-19 11:31
閱讀 2396·2019-08-30 15:55
閱讀 2717·2019-08-30 14:11
閱讀 3157·2019-08-30 13:45
閱讀 1371·2019-08-29 18:41
閱讀 1147·2019-08-29 16:18