首頁 web前端 js教程 功能組成:可維護代碼的構建塊

功能組成:可維護代碼的構建塊

Feb 17, 2025 am 11:19 AM

Function Composition: Building Blocks for Maintainable Code

JavaScript 函數組合:構建更易維護的代碼

JavaScript 函數組合是一種將多個簡單函數組合成單個更複雜函數的技術,這些函數按邏輯順序對給定數據執行子函數操作。函數應用的順序會產生不同的結果。

為了編寫可維護的代碼,理解每個被組合函數的返回類型至關重要,以確保下一個函數可以正確處理它。 JavaScript 不會阻止組合返回不合適類型函數,因此這部分責任落在程序員身上。

對不熟悉函數式編程範式的人來說,組合函數可能會使代碼看起來很複雜。但是,隨著 ES2015 語法的出現,使用箭頭函數,可以一行代碼創建簡單的組合函數,而無需特殊的組合方法。

組合函數應該是純函數,這意味著每次將特定值傳遞給函數時,函數都應返回相同的結果,並且函數不應產生改變自身外部值的副作用。這將產生更簡潔、更易讀的代碼。

本文由 Jeff Mott、Dan Prince 和 Sebastian Seitz 共同評審。感謝所有 SitePoint 的同行評審者,使 SitePoint 的內容達到最佳狀態!

Function Composition: Building Blocks for Maintainable Code

函數式思維的優勢之一是能夠使用小型、易於理解的單個函數來構建複雜的功能。 但有時這需要反向思考問題,而不是正向思考,以便找出如何創建最優雅的解決方案。在本文中,我將採用循序漸進的方法來檢查 JavaScript 中的函數組合,並演示它如何產生更易於理解且錯誤更少的代碼。

嵌套函數

組合是一種技術,它允許你將兩個或多個簡單函數組合成一個更複雜的函數,該函數按邏輯順序對傳入的任何數據執行每個子函數。要獲得此結果,你需要將一個函數嵌套在另一個函數中,並對內部函數的結果重複執行外部函數的操作,直到產生結果。並且結果可能因函數應用的順序而異。這可以使用我們已經在 JavaScript 中熟悉的編程技術輕鬆演示,方法是將函數調用作為參數傳遞給另一個函數:

function addOne(x) {
  return x + 1;
}
function timesTwo(x) {
  return x * 2;
}
console.log(addOne(timesTwo(3))); //7
console.log(timesTwo(addOne(3))); //8
登入後複製
登入後複製
登入後複製
登入後複製

在這種情況下,我們定義了一個 addOne() 函數來為一個值加 1,以及一個 timesTwo() 函數將一個值乘以 2。通過將一個函數的結果作為另一個函數的參數傳入,我們可以看到如何將其中一個嵌套在另一個中會產生不同的結果,即使初始值相同也是如此。內部函數先執行,然後結果傳遞給外部函數。

命令式組合

如果你想重複執行相同的操作序列,定義一個新函數來自動應用第一個函數和第二個函數可能會很方便。這可能看起來像這樣:

function addOne(x) {
  return x + 1;
}
function timesTwo(x) {
  return x * 2;
}
console.log(addOne(timesTwo(3))); //7
console.log(timesTwo(addOne(3))); //8
登入後複製
登入後複製
登入後複製
登入後複製

在這種情況下,我們手動將這兩個函數按特定順序組合在一起。我們創建了一個新函數,該函數首先將傳遞的值分配給 holder 變量,然後通過執行第一個函數,然後是第二個函數來更新該變量的值,最後返回該 holder 的值。 (請注意,我們使用名為holder 的變量來臨時保存我們傳入的值。對於這樣一個簡單的函數,額外的局部變量似乎是多餘的,但即使在命令式JavaScript 中,將傳入函數的參數值視為常量也是一個好習慣。局部修改它們是可能的,但這會造成關於在函數的不同階段調用時參數值是什麼的混淆。)類似地,如果我們想創建一個另一個新函數以相反的順序應用這兩個較小的函數,我們可以執行以下操作:

// ...来自上面的先前函数定义
function addOneTimesTwo(x) {
  var holder = x;
  holder = addOne(holder);
  holder = timesTwo(holder);
  return holder;
}
console.log(addOneTimesTwo(3)); //8
console.log(addOneTimesTwo(4)); //10
登入後複製
登入後複製

當然,這段代碼開始看起來非常重複。我們的兩個新的組合函數幾乎完全相同,只是它們調用的兩個較小函數的執行順序不同。我們需要簡化它(就像不要重複自己一樣)。此外,使用像這樣改變其值的臨時變量並不是很函數式,即使它隱藏在我們正在創建的組合函數內部也是如此。底線:我們可以做得更好。

創建函數式組合

讓我們創建一個組合函數,它可以採用現有的函數並將它們按我們想要的順序組合在一起。為了以一致的方式做到這一點,而無需每次都處理內部細節,我們必須決定要將函數作為參數傳入的順序。我們有兩個選擇。參數將分別是函數,它們可以從左到右或從右到左執行。也就是說,使用我們提出的新函數,compose(timesTwo, addOne) 可以表示 timesTwo(addOne()) 從右到左讀取參數,或者 addOne(timesTwo()) 從左到右讀取參數。從左到右執行參數的優點是它們將以英語相同的閱讀方式讀取,這與我們命名組合函數 timesTwoAddOne() 以暗示乘法應在加法之前發生的方式非常相似。我們都知道邏輯命名對於簡潔易讀的代碼的重要性。從左到右執行參數的缺點是待操作的值必須放在前面。但是,將值放在前面使得將來用其他函數組合結果函數不太方便。為了很好地解釋這種邏輯背後的思想,你無法超越 Brian Lonsdorf 的經典視頻 Hey Underscore, You’re Doing it Wrong。 (儘管應該注意的是,現在Underscore 有一個fp 選項可以幫助解決Brian 在將Underscore 與函數式編程庫(例如lodash-fp 或Ramda)一起使用時討論的函數式編程問題。)無論如何,我們真正想要做的是首先傳入所有配置數據,然後最後傳入要操作的值。因此,將我們的組合函數定義為讀取其參數並從右到左應用它們最合乎邏輯。因此,我們可以創建一個看起來像這樣的基本組合函數:

function addOne(x) {
  return x + 1;
}
function timesTwo(x) {
  return x * 2;
}
console.log(addOne(timesTwo(3))); //7
console.log(timesTwo(addOne(3))); //8
登入後複製
登入後複製
登入後複製
登入後複製

使用這個非常簡單的組合函數,我們可以更簡單地構建我們之前的兩個複雜函數,並看到結果相同:

// ...来自上面的先前函数定义
function addOneTimesTwo(x) {
  var holder = x;
  holder = addOne(holder);
  holder = timesTwo(holder);
  return holder;
}
console.log(addOneTimesTwo(3)); //8
console.log(addOneTimesTwo(4)); //10
登入後複製
登入後複製

雖然這個簡單的組合函數有效,但它並沒有考慮許多限制其靈活性和適用性的問題。例如,我們可能想要組合兩個以上的函數。此外,我們在此過程中會丟失這些信息。我們可以解決這些問題,但為了掌握組合的工作原理,這不是必需的。與其自己編寫,不如從現有的函數式庫(例如 Ramda)繼承更強大的組合,默認情況下,它確實考慮了參數從右到左的順序。

類型是你的責任

重要的是要記住,程序員有責任知道每個被組合函數的返回類型,以便下一個函數可以正確處理它。與執行嚴格類型檢查的純函數式編程語言不同,JavaScript 不會阻止你嘗試組合返回不合適類型值的函數。你不僅限於傳遞數字,甚至不限於從一個函數到下一個函數保持相同的變量類型。但是你負責確保你正在組合的函數已準備好處理前一個函數返回的任何值。

考慮你的受眾

始終記住,其他人將來可能需要使用或修改你的代碼。在傳統的 JavaScript 代碼中使用組合對於不熟悉函數式編程範式的人來說可能會顯得複雜。目標是更簡潔、更易於閱讀和維護的代碼。但是,隨著 ES2015 語法的出現,甚至可以使用箭頭函數將簡單的組合函數作為單行調用來創建,而無需特殊的組合方法:

function addOne(x) {
  return x + 1;
}
function timesTwo(x) {
  return x * 2;
}
console.log(addOne(timesTwo(3))); //7
console.log(timesTwo(addOne(3))); //8
登入後複製
登入後複製
登入後複製
登入後複製

今天就開始組合吧

與所有函數式編程技術一樣,重要的是要記住你的組合函數應該是純函數。簡而言之,這意味著每次將特定值傳遞給函數時,函數都應返回相同的結果,並且函數不應產生改變自身外部值的副作用。當您有一組想要應用於數據的相關功能,並且您可以將該功能的組件分解為可重用且易於組合的函數時,組合嵌套非常方便。與所有函數式編程技術一樣,我建議謹慎地將組合添加到你的現有代碼中以熟悉它。如果你做對了,結果將是更簡潔、更乾燥、更易讀的代碼。難道這不是我們都想要的嗎?

(以下為FAQ,已根據原文進行調整和精簡,並避免重複信息)

關於函數組合和可維護代碼的常見問題

  • 什麼是編程中的函數組合? 函數組合是將簡單函數組合成更複雜函數的概念。你可以像搭積木一樣,用這些小型可重用的函數創建複雜、強大的功能。這有助於使代碼更易讀、更易維護和更具可擴展性。

  • 函數組合如何促進可維護的代碼? 函數組合通過鼓勵使用小型、可重用的函數來促進可維護性。這些函數更容易理解、測試和調試。當這些小型函數組合在一起以創建更複雜的功能時,更容易查明和修復可能出現的任何問題。這種模塊化方法還可以更容易地更新或修改代碼的某些部分,而不會影響整個系統。

  • 編寫可維護代碼的最佳實踐是什麼? 編寫可維護的代碼涉及多項最佳實踐,包括:保持函數小巧且專注於單一任務;使用有意義的變量和函數名稱;對代碼進行註釋以解釋代碼邏輯背後的“原因”;遵循一致的編碼風格和結構。

  • 函數組合與函數式編程有何關係? 函數組合是函數式編程中的一個基本概念。函數式編程是一種將計算視為數學函數的求值並避免更改狀態和可變數據的範例。在這種範例中,函數組合在從更簡單的函數構建更複雜的函數中起著至關重要的作用,從而提高了代碼的可重用性和可維護性。

  • 實現函數組合的挑戰是什麼? 函數組合雖然有很多好處,但也可能帶來挑戰。一個挑戰是,如果管理不當,它可能會導致難以閱讀的代碼,尤其是在組合多個函數時。在組合函數鏈中處理錯誤和異常也可能很困難。但是,可以通過良好的編碼實踐和正確使用函數組合來減輕這些挑戰。

  • 函數組合如何改進代碼測試? 函數組合可以使代碼測試更輕鬆、更高效。由於組合函數是由較小、獨立的函數組成的,因此你可以單獨測試每個小型函數。這使得更容易隔離和修復錯誤。它還促進了單元測試的實踐,其中軟件的每個部分都單獨進行測試以確保其正常工作。

以上是功能組成:可維護代碼的構建塊的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

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

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

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

熱門話題

Java教學
1665
14
CakePHP 教程
1424
52
Laravel 教程
1322
25
PHP教程
1270
29
C# 教程
1250
24
JavaScript引擎:比較實施 JavaScript引擎:比較實施 Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

Python vs. JavaScript:學習曲線和易用性 Python vs. JavaScript:學習曲線和易用性 Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

從C/C到JavaScript:所有工作方式 從C/C到JavaScript:所有工作方式 Apr 14, 2025 am 12:05 AM

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

JavaScript和Web:核心功能和用例 JavaScript和Web:核心功能和用例 Apr 18, 2025 am 12:19 AM

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

JavaScript在行動中:現實世界中的示例和項目 JavaScript在行動中:現實世界中的示例和項目 Apr 19, 2025 am 12:13 AM

JavaScript在現實世界中的應用包括前端和後端開發。 1)通過構建TODO列表應用展示前端應用,涉及DOM操作和事件處理。 2)通過Node.js和Express構建RESTfulAPI展示後端應用。

了解JavaScript引擎:實施詳細信息 了解JavaScript引擎:實施詳細信息 Apr 17, 2025 am 12:05 AM

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python vs. JavaScript:社區,圖書館和資源 Python vs. JavaScript:社區,圖書館和資源 Apr 15, 2025 am 12:16 AM

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

Python vs. JavaScript:開發環境和工具 Python vs. JavaScript:開發環境和工具 Apr 26, 2025 am 12:09 AM

Python和JavaScript在開發環境上的選擇都很重要。 1)Python的開發環境包括PyCharm、JupyterNotebook和Anaconda,適合數據科學和快速原型開發。 2)JavaScript的開發環境包括Node.js、VSCode和Webpack,適用於前端和後端開發。根據項目需求選擇合適的工具可以提高開發效率和項目成功率。

See all articles