函式式 JavaScript 簡介

Delostik發表於2016-03-10

你肯定聽說過JavaScript是一個函式式語言,或者至少知道他支援函數語言程式設計。但是究竟什麼是函數語言程式設計?對於這個問題,如果你打算比較通用的程式設計正規化,函式式的實現跟我們平時寫的JavaScript又有什麼不同?

好訊息是在程式設計正規化方面JavaScript沒有那麼講究,你可以混入命令式(Imperative Programming)、物件導向、原型和函式式程式碼等等,只要你覺得合適,都能得到一樣的結果。但是壞訊息也因它而起,JavaScript在同樣的程式碼庫下同時提供了眾多程式設計風格,所以你需要根據程式碼的可維護性、可讀性和效能選擇合適的程式設計方式。

函式式JavaScript並不是一定要用於整個專案中來體現它的價值。學習一點函式式的方法可以在我們構建專案時提供一些參考和幫助,而不論我們喜歡哪種方式。學習一些函式式模式和技術可以幫助我們寫出更整潔、優雅的JavaScript程式碼,不論我們是不是真的用它。

這一小段程式碼中做了很多事:定義了一個全域性變數;字串值被傳來傳去,並被函式修改;還夾雜著原生JavaScript的DOM方法。函式名不是很有描述力,一定程度上因為這一切都依賴於不確定存在或不存在的上下文。但是如果你碰巧在瀏覽器執行了這段程式碼,而且網頁中定義了一個<button id="main_button">,你會收到可輸入文字的對話方塊提示,會看到那串被首字母大寫了的文字。

像這種命令式程式碼會從頂部開始執行(如果不考慮variable hoisting的情況)。但是我們仍然可以利用JavaScript的物件導向能力來提高程式碼的可讀性和整潔度。

物件導向的JavaScript

幾年後,開發者開始注意到像瀏覽器這樣的共享環境下的指令式程式設計的問題。一段JavaScript程式碼中定義的全域性變數可能會破壞另一個全域性變數。程式碼執行的順序和效果無法預測,尤其在網路延遲和渲染時間的影響下。

後來出現了一些好辦法來封裝JS程式碼,讓它能更好地跟DOM工作。比如下面這段程式碼是前面程式碼的一種改寫,使用了物件導向的方法:

在物件導向的版本中,建構函式模擬了一個類供我們設計我們想要的物件,方法定義在物件的原型中來降低記憶體使用。所有的程式碼都封閉在一個匿名的及時呼叫函式表示式中,所以它不會汙染全域性作用域。”use strict”強制使用最新的JavaScript引擎,onclick方法被新引入的addEventListner代替,畢竟沒人再使用比IE8還古董的瀏覽器了。這段程式碼可以被插入在<body>段的最後,使得所有的DOM載入完成後才執行,這時候<button>才可用。

函式式JavaScript

相比我們開始說的命令式程式碼,物件導向確實能使程式碼更整潔、模組化更好,但我們看能否通過解決它的一些缺點來使它更完美。如果我們能通過JavaScript的一些內建特性,把函式當“第一類物件”看待,我們的程式碼會更加乾淨、穩定、易擴充。

發現這個版本短了多少沒?我們制定一了capify和processWords兩個函式,每個函式都是pure的,也就是說他們不依賴於呼叫他們的程式碼的狀態。函式不會改變他們之外的變數。針對給定的任意引數,返回唯一的結果。由於這些改進,新的函式易於測試,也很容易被移植。

剛才那段程式碼中可能有個函式你沒見過,我們在Array上使用map方法,可以對Array上每個元素應用fn函式(fn是傳入的引數)。執行在現代瀏覽器和服務端的實現了ES5的JavaScript為我們提供了這個方便的函式。這裡不需要使用for迴圈,只使用一個map,可以避免使用迴圈變數,提高程式碼的整潔度和可讀性。

對函式式的思考

你用為了函式正規化而拋棄使用的一切,而是在你做下一個專案的時候,可以用函式的思維來考慮一下下面的問題:

  • 我的函式依賴呼叫上下文嗎?他們是獨立的嗎?
  • 我可以把函式寫成對某個輸入總有相同返回值的嗎?
  • 我的函式不改變函式外的變數嗎?
  • 如果我想要在其他專案中使用這個函式,我需要修改他們嗎?

這篇介紹僅僅是揭露了函式式JavaScript的表面,但希望它能引起你的探究慾望而學到更多。

相關文章