本文將簡要介紹函數式編程的概念,並闡述五種提升 JavaScript 代碼函數式風格的方法。
核心要點
- 函數式編程是一種編程範式,它使用函數及其應用而非命令列表。它更抽象,起源於數學。 JavaScript 特別適合函數式編程,因為函數是第一類對象。
- 純函數是函數式編程的關鍵部分。給定相同的參數,它們始終返回相同的值,並且不會更改函數作用域之外的內容。它們使您的代碼更易於移植和測試。
- 在函數式編程中,變量應保持不變。設置變量後,它應在整個程序中保持該狀態。這可以通過始終使用
const
聲明變量來實現。 - 建議在 JavaScript 的函數式編程中使用箭頭函數和三元運算符。箭頭函數具有隱式返回值,這有助於可視化輸入到輸出的映射。三元運算符是始終返回值的表達式,因此對於確保存在返回值很有用。
- 應避免在函數式編程中使用
for
循環,因為它們依賴於可變狀態。應改用遞歸和高階數組方法。此外,應避免類型強制以保持類型一致性。這可以通過在聲明函數之前編寫類型聲明註釋來實現。
什麼是函數式編程?
函數式編程是一種編程範式,它使用函數及其應用,而不是在命令式編程語言中使用的命令列表。
這是一種更抽象的編程風格,其根源在於數學——特別是稱為 lambda 演算的數學分支,該分支由數學家 Alonzo Church 於 1936 年設計為可計算性的形式模型。它由表達式和函數組成,這些表達式和函數將一個表達式映射到另一個表達式。從根本上說,這就是我們在函數式編程中所做的:我們使用函數將值轉換為不同的值。
本文作者近年來愛上了函數式編程。我們開始使用鼓勵更函數式風格的 JavaScript 庫,然後通過學習如何在 Haskell 中編寫代碼直接跳入深水區。
Haskell 是一種純函數式編程語言,開發於 20 世紀 90 年代,類似於 Scala 和 Clojure。使用這些語言,您將被迫採用函數式風格進行編碼。學習 Haskell 使我們真正了解了函數式編程提供的所有優勢。
JavaScript 是一種多範式語言,因為它可以用於以命令式、面向對像或函數式風格進行編程。但是,它確實特別適合函數式風格,因為函數是第一類對象,這意味著它們可以賦值給變量。這也意味著函數可以作為參數傳遞給其他函數(通常稱為回調),也可以作為其他函數的返回值。返回其他函數或接受其他函數作為參數的函數稱為高階函數,它們是函數式編程的基礎部分。
近年來,以函數式風格編程 JavaScript 變得越來越流行,尤其是在 React 興起之後。 React 使用適合函數式方法的聲明式 API,因此紮實掌握函數式編程原理將改進您的 React 代碼。
為什麼函數式編程如此優秀?
簡而言之,函數式編程語言通常會導致代碼簡潔、清晰且優雅。代碼通常更容易測試,並且可以在多線程環境中運行而不會出現任何問題。
如果您與許多不同的程序員交談,您可能會從每個人那裡獲得關於函數式編程的完全不同的意見——從那些絕對討厭它的人到那些絕對喜歡它的人。我們(本文作者)站在“喜歡它”的一端,但我們完全理解它並非每個人的菜,尤其因為它與通常教授的編程方式大相徑庭。
但是,一旦您掌握了函數式編程,並且一旦思維過程點擊到位,它就會成為第二天性,並改變您編寫代碼的方式。
規則 1:淨化您的函數
函數式編程的關鍵部分是確保您編寫的函數是“純”的。如果您不熟悉這個術語,純函數基本上滿足以下條件:
- 它具有引用透明性。這意味著,給定相同的參數,函數將始終返回相同的值。任何函數調用都可以用返回值替換,程序仍然會以相同的方式運行。
- 它沒有副作用。這意味著函數不會在函數作用域之外進行任何更改。這可能包括更改全局值、記錄到控制台或更新 DOM。
純函數必須至少有一個參數,並且必須返回值。如果您仔細考慮,如果它們不接受任何參數,它們將沒有任何數據可以使用,如果它們不返回值,那麼函數的意義何在?
純函數一開始可能看起來並非完全必要,但使用不純函數會導致程序發生整體變化,從而導致一些嚴重的邏輯錯誤!
例如:
// 不纯 let minimum = 21; const checkAge = (age) => age >= minimum; // 纯 const checkAge = (age) => { const minimum = 21; return age >= minimum; };
在不純函數中,checkAge
函數依賴於可變變量 minimum
。例如,如果稍後在程序中更新 minimum
變量,則 checkAge
函數可能會使用相同的輸入返回布爾值。
假設我們運行以下代碼:
checkAge(20); // false
現在,假設稍後在代碼中,changeToUK()
函數將 minimum
的值更新為 18。
然後,假設我們運行以下代碼:
// 不纯 let minimum = 21; const checkAge = (age) => age >= minimum; // 纯 const checkAge = (age) => { const minimum = 21; return age >= minimum; };
現在,checkAge
函數評估為不同的值,儘管給出了相同的輸入。
純函數使您的代碼更易於移植,因為它們不依賴於作為參數提供的任何值之外的任何其他值。返回值永遠不會改變的事實使純函數更容易測試。
一致地編寫純函數還可以消除發生突變和副作用的可能性。
突變是函數式編程中的一大危險信號,如果您想了解更多信息,可以閱讀關於它們在《JavaScript 中變量賦值和突變指南》中的內容。
為了使您的函數更易於移植,請確保您的函數始終保持純淨。
規則 2:保持變量不變
聲明變量是任何程序員學習的第一件事之一。它變得微不足道,但在使用函數式編程風格時卻極其重要。
函數式編程的關鍵原則之一是,一旦設置了變量,它就會在整個程序中保持該狀態。
這是顯示代碼中變量的重新賦值/重新聲明如何成為災難的最簡單的示例:
checkAge(20); // false
如果您仔細考慮,n
的值不可能同時為 10 和 11;這在邏輯上說不通。
命令式編程中的一種常見編碼實踐是使用以下代碼遞增值:
checkAge(20); // true
在數學中,語句 x = x 1
是不合邏輯的,因為如果您從兩邊減去 x
,您將得到 0 = 1
,這顯然是不正確的。
因此,在 Haskell 中,您不能將變量賦值給一個值,然後將其重新賦值給另一個值。為了在 JavaScript 中實現這一點,您應該遵循始終使用 const
聲明變量的規則。
規則 3:使用箭頭函數
在數學中,函數的概念是將一組值映射到另一組值的概念。下圖顯示了通過平方將左側的值集映射到右側的值集的函數:
這就是使用箭頭表示法在數學中編寫它的方式:f: x → x²。這意味著函數 f 將值 x 映射到 x²。
我們可以使用箭頭函數幾乎以相同的方式編寫此函數:
const n = 10; n = 11; // TypeError: "Attempted to assign to readonly property."
在 JavaScript 中使用函數式風格的一個關鍵特徵是使用箭頭函數而不是常規函數。當然,這確實歸結為風格,使用箭頭函數而不是常規函數實際上不會影響代碼的“函數式”程度。
但是,在使用函數式編程風格時,最難適應的事情之一是將每個函數都視為輸入到輸出的映射的思維方式。沒有所謂的過程。我們發現使用箭頭函數可以幫助我們更好地理解函數的過程。
箭頭函數具有隱式返回值,這確實有助於可視化此映射。
箭頭函數的結構——尤其是它們的隱式返回值——有助於鼓勵編寫純函數,因為它們的結構實際上是“輸入映射到輸出”:
// 不纯 let minimum = 21; const checkAge = (age) => age >= minimum; // 纯 const checkAge = (age) => { const minimum = 21; return age >= minimum; };
另一件事是我們喜歡強調的,尤其是在編寫箭頭函數時,是使用三元運算符。如果您不熟悉三元運算符,它們是內聯 if...else
語句,形式為 condition ? value if true : value if false
。
您可以閱讀更多關於它們在《快速提示:如何在 JavaScript 中使用三元運算符》中的內容。
在函數式編程中使用三元運算符的主要原因之一是 else
語句的必要性。程序必須知道如果不滿足原始條件該怎麼做。例如,Haskell 會強制執行 else
語句,如果沒有給出 else
語句,它將返回錯誤。
使用三元運算符的另一個原因是它們是始終返回值的表達式,而不是可以用於執行可能具有副作用的操作的 if-else
語句。這對於箭頭函數特別有用,因為它意味著您可以確保存在返回值並保持輸入到輸出映射的圖像。如果您不確定語句和表達式之間的細微差別,那麼關於語句與表達式的指南非常值得一讀。
為了說明這兩個條件,以下是一個使用三元運算符的簡單箭頭函數示例:
checkAge(20); // false
action
函數將根據 state
參數的值返回“eat”或“sleep”的值。
因此,總之:在使您的代碼更具函數式時,您應該遵循以下兩條規則:
- 使用箭頭表示法編寫函數
- 將
if...else
語句替換為三元運算符
規則 4:刪除 for 循環
鑑於使用 for
循環編寫迭代代碼在編程中非常常見,說要避免它們似乎很奇怪。事實上,當我們第一次發現 Haskell 甚至沒有任何類型的 for
循環操作時,我們難以理解如何實現某些標準操作。但是,有一些非常好的理由說明為什麼 for
循環不會出現在函數式編程中,我們很快發現每種類型的迭代過程都可以在不使用 for
循環的情況下實現。
不使用 for
循環最重要的原因是它們依賴於可變狀態。讓我們來看一個簡單的求和函數:
checkAge(20); // true
如您所見,我們必須在 for
循環本身以及我們在 for
循環中更新的變量中使用 let
。
如前所述,這通常是函數式編程中的不良做法,因為函數式編程中的所有變量都應該是不可變的。
如果我們想編寫所有變量都是不可變的代碼,我們可以使用遞歸:
const n = 10; n = 11; // TypeError: "Attempted to assign to readonly property."
如您所見,沒有變量被更新。
我們當中的數學家顯然會知道所有這些代碼都是不必要的,因為我們可以只使用巧妙的求和公式 0.5*n*(n 1)。但這是一種很好的方法,可以說明 for
循環的可變性與遞歸之間的區別。
但是,遞歸併不是解決可變性問題的唯一解決方案,尤其是在處理數組時。 JavaScript 具有許多內置的高階數組方法,這些方法可以遍歷數組中的值而無需更改任何變量。
例如,假設我們要將 1 加到數組中的每個值。使用命令式方法和 for
循環,我們的函數可能如下所示:
// 不纯 let minimum = 21; const checkAge = (age) => age >= minimum; // 纯 const checkAge = (age) => { const minimum = 21; return age >= minimum; };
但是,我們可以使用 JavaScript 的內置 map
方法並編寫如下所示的函數:
checkAge(20); // false
如果您以前從未見過map
函數,那麼絕對值得了解它們——以及JavaScript 的所有內置高階數組方法,例如filter
,尤其如果您真的對JavaScript 中的函數式編程感興趣。您可以在《不可變數組方法:如何編寫非常清晰的 JavaScript 代碼》中找到更多關於它們的信息。
Haskell 完全沒有 for
循環。為了使您的 JavaScript 更具函數式,請嘗試通過使用遞歸和內置的高階數組方法來避免使用 for
循環。
規則 5:避免類型強制
在使用 JavaScript 等不需要類型聲明的語言進行編程時,很容易忘記數據類型的重要性。 JavaScript 中使用的七種原始數據類型是:
- Number
- String
- Boolean
- Symbol
- BigInt
- Undefined
- Null
Haskell 是一種強類型語言,需要類型聲明。這意味著在任何函數之前,您都需要使用 Hindley-Milner 系統指定進入的數據類型和輸出的數據類型。
例如:
checkAge(20); // true
這是一個非常簡單的函數,它將兩個數字(x 和 y)加在一起。對於每個函數,包括像這樣的非常簡單的函數,都必須向程序解釋數據類型似乎有點荒謬,但這最終有助於顯示函數的預期工作方式及其預期返回的內容。這使得代碼更容易調試,尤其是在代碼變得更複雜時。
類型聲明遵循以下結構:
const n = 10; n = 11; // TypeError: "Attempted to assign to readonly property."
類型強制在使用 JavaScript 時可能是一個大問題,JavaScript 具有各種可以用來(甚至濫用)繞過數據類型不一致的技巧。以下是最常見的技巧以及如何避免它們:
- 連接。 “Hello” 5 評估為“Hello5”,這並不一致。如果您想將字符串與數值連接起來,您應該編寫“Hello” String(5)。
- 布爾語句和 0。在 JavaScript 中,
if
語句中的 0 值等效於 false。這可能導致懶惰的編程技術,忽略檢查數值數據是否等於 0。
例如:
// 不纯 let minimum = 21; const checkAge = (age) => age >= minimum; // 纯 const checkAge = (age) => { const minimum = 21; return age >= minimum; };
這是一個評估數字是否為偶數的函數。它使用 !
符號將 n % 2
的結果強制轉換為布爾值,但 n % 2
的結果不是布爾值,而是一個數字(0 或 1)。
像這樣的技巧,雖然看起來很聰明,並且減少了您編寫的代碼量,但它們破壞了函數式編程的類型一致性規則。因此,編寫此函數的最佳方法如下所示:
checkAge(20); // false
另一個重要概念是確保數組中的所有數據值都是相同類型。 JavaScript 不會強制執行此操作,但如果沒有相同類型,當您想要使用高階數組方法時可能會導致問題。
例如,一個將數組中所有數字相乘並返回結果的乘積函數可以用以下類型聲明註釋編寫:
checkAge(20); // true
在這裡,類型聲明清楚地表明函數的輸入是一個包含 Number 類型元素的數組,但它只返回一個數字。類型聲明清楚地說明了此函數的預期輸入和輸出。顯然,如果數組不只包含數字,則此函數將無法工作。
Haskell 是一種強類型語言,而 JavaScript 是一種弱類型語言,但為了使您的 JavaScript 更具函數式,您應該在聲明函數之前編寫類型聲明註釋,並確保避免類型強制快捷方式。
我們還應該在這裡提到,如果您想要 JavaScript 的強類型替代方案,該替代方案將為您強制執行類型一致性,那麼您可以轉向 TypeScript。
結論
總而言之,以下五個規則將幫助您實現函數式代碼:
- 保持您的函數純淨。
- 始終使用const聲明變量和函數。
- 對函數使用箭頭表示法。
- 避免使用
for
循環。 - 使用類型聲明註釋並避免類型強制快捷方式。
雖然這些規則不能保證您的代碼是純函數式的,但它們將在很大程度上使其更具函數式,並有助於使其更簡潔、更清晰且更容易測試。
我們真的希望這些規則能像幫助我們一樣幫助您!我們兩人都是函數式編程的忠實粉絲,我們強烈建議任何程序員使用它。
如果您想進一步深入研究函數式 JavaScript,我們強烈建議您閱讀《弗里斯比教授關於函數式編程的大部分充分指南》,該指南可以在線免費獲取。如果您想全力以赴學習 Haskell,我們建議您使用 Try Haskell 交互式教程並閱讀優秀的《學習 Haskell 以獲得更大的好處》一書,該書也可以在線免費閱讀。
關於 JavaScript 函數式編程的常見問題
什麼是 JavaScript 中的函數式編程? 函數式編程是一種編程範式,它將計算視為數學函數的評估,並避免更改狀態和可變數據。在 JavaScript 中,它涉及使用函數作為一等公民並避免副作用。
什麼是 JavaScript 中的一等函數? JavaScript 中的一等函數意味著函數被視為與任何其他變量一樣。它們可以賦值給變量,作為參數傳遞給其他函數,並作為值從其他函數返回。
什麼是函數式編程中的不變性? 不變性是指一旦創建對象,就不能更改它。在 JavaScript 函數式編程的上下文中,這意味著在初始化變量或數據結構後避免修改它們。
什麼是高階函數? 高階函數是將其他函數作為參數或返回函數作為結果的函數。它們支持函數的組合,使創建模塊化和可重用代碼更容易。
是否有任何庫/框架可以促進 JavaScript 中的函數式編程? 是的,一些庫和框架(例如 Ramda 和 lodash)提供了支持 JavaScript 函數式編程概念的實用程序和函數。它們可以幫助簡化和增強函數式編程實踐。
以上是使您的JavaScript更具功能性的5種方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

Python和JavaScript的主要區別在於類型系統和應用場景。 1.Python使用動態類型,適合科學計算和數據分析。 2.JavaScript採用弱類型,廣泛用於前端和全棧開發。兩者在異步編程和性能優化上各有優勢,選擇時應根據項目需求決定。

選擇Python還是JavaScript取決於項目類型:1)數據科學和自動化任務選擇Python;2)前端和全棧開發選擇JavaScript。 Python因其在數據處理和自動化方面的強大庫而備受青睞,而JavaScript則因其在網頁交互和全棧開發中的優勢而不可或缺。

Python和JavaScript各有優勢,選擇取決於項目需求和個人偏好。 1.Python易學,語法簡潔,適用於數據科學和後端開發,但執行速度較慢。 2.JavaScript在前端開發中無處不在,異步編程能力強,Node.js使其適用於全棧開發,但語法可能複雜且易出錯。

javascriptisnotbuiltoncorc; sanInterpretedlanguagethatrunsonenginesoftenwritteninc.1)JavascriptwasdesignedAsignedAsalightWeight,drackendedlanguageforwebbrowsers.2)Enginesevolvedfromsimpleterterpretpretpretpretpreterterpretpretpretpretpretpretpretpretpretcompilerers,典型地,替代品。

JavaScript可用於前端和後端開發。前端通過DOM操作增強用戶體驗,後端通過Node.js處理服務器任務。 1.前端示例:改變網頁文本內容。 2.後端示例:創建Node.js服務器。

選擇Python還是JavaScript應基於職業發展、學習曲線和生態系統:1)職業發展:Python適合數據科學和後端開發,JavaScript適合前端和全棧開發。 2)學習曲線:Python語法簡潔,適合初學者;JavaScript語法靈活。 3)生態系統:Python有豐富的科學計算庫,JavaScript有強大的前端框架。

JavaScript框架的強大之處在於簡化開發、提升用戶體驗和應用性能。選擇框架時應考慮:1.項目規模和復雜度,2.團隊經驗,3.生態系統和社區支持。

引言我知道你可能會覺得奇怪,JavaScript、C 和瀏覽器之間到底有什麼關係?它們之間看似毫無關聯,但實際上,它們在現代網絡開發中扮演著非常重要的角色。今天我們就來深入探討一下這三者之間的緊密聯繫。通過這篇文章,你將了解到JavaScript如何在瀏覽器中運行,C 在瀏覽器引擎中的作用,以及它們如何共同推動網頁的渲染和交互。 JavaScript與瀏覽器的關係我們都知道,JavaScript是前端開發的核心語言,它直接在瀏覽器中運行,讓網頁變得生動有趣。你是否曾經想過,為什麼JavaScr


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

Dreamweaver Mac版
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。