作者:Martin Novák
讓我們談談什麼是:lambdas(匿名函式)、 first-class functions(頭等函式)、higher-order functions(高階函式)、unary functions(一元函式)、currying(柯里化 )和pure functions(純函式)。
如果您不清楚命令式和宣告式程式設計之間的區別,可以看我的文章: Imperative versus declarative code… what’s the difference?
什麼是Lambdas(匿名)=> 箭頭函式?
Lambdas (λ) 在 JavaScript 作為arrow functions(箭頭函式)被廣為所知:
// this is your regular named function in JavaScript
function namedFunction (a, b) {
return a + b;
}
// this is a lambda, i.e. an arrow function
const lambda = (a, b) => a + b;
複製程式碼
術語lambda是一個正式的數學邏輯系統,起源於lambda演算。Lambda演算是由圖靈完成的,它代表了能夠構建任何圖靈機的通用計算模型。 Lambda expressions(匿名函式表示式) 是函數語言程式設計的基石。如果它對你有所幫助,只需將它視為函式的新縮短語法就行。然而,在物件或類中使用它們時要注意this的指向。
什麼是first-class functions(頭等函式)?
First-class type 意味著,該型別可以用作變數的值。在JavaScript中一個字串是頭等型別,一個函式也是頭等型別。所以函式可以接受其他函式作為引數,並返回函式作為返回值。
在繫結事件監聽器時,函式作為first-class被使用:
const handler = () => console.log ('I am function');
document.addEventListener ('click', handler);
複製程式碼
什麼是higher-order functions(高階函式)?
高階函式是一個接受其他函式作為引數或將函式作為返回值返回的函式。 __First-order function(一階函式)__是一個函式,它不接受其他函式作為引數,並且不返回函式作為其返回值。
const firstOrder = () => console.log ('First order strikes back!');
const higherOrder = whoStrikesBack => whoStrikesBack ();
higherOrder (firstOrder);
複製程式碼
什麼是unary functions(一元函式)?
該術語涉及一個函式接受一些引數的元數。一元函式(i.e. monadic)是一個只接受一個引數的函式。
const unaryFunction = message => console.log (message);
const binaryFunction = (color, message) =>
console.log (`%c${message}`, `color:${color}`);
const ternaryFunction = (fnc, color, message) =>
fnc (`%c${message}`, `color:${color}`);
複製程式碼
什麼是currying(柯里化)?
Currying(柯里化)是一個帶有多個引數的函式並將其轉換為函式序列的過程,每個函式只有一個引數。
一個有n個引數的函式,可以使用柯里化將它變成一個一元函式。
const binaryFunction = (a, b) => a + b;
const curryUnaryFunction = a => b => a + b;
curryUnaryFunction (1); // returns a function: b => 1 + b
curryUnaryFunction (1) (2); // returns the number 3
複製程式碼
Currying(柯里化)以數學家 Haskell Curry的名字命名,不是吃的。
柯里化函式非常適合提高程式碼的可重用性和函式式結構。想了解更多,請參考: JavaScript ES6 curry functions with practical examples。它可能會讓人習慣,但是我現在寫的所有函式都歸功於柯里化。
什麼是pure functions(純函式)?
純函式是一種其返回值僅由其引數決定,沒有任何副作用的函式。
這意味著如果你在整個應用程式中的不同的一百個地放呼叫一個純函式相同的引數一百次,該函式始終返回相同的值。純函式不會更改或讀取外部狀態。
let myArray = [];
const impureAddNumber = number => myArray.push (number);
const pureAddNumber = number => anArray =>
anArray.concat ([number]);
console.log (impureAddNumber (2)); // returns 1
console.log (myArray); // returns [2]
console.log (pureAddNumber (3) (myArray)); // returns [2, 3]
console.log (myArray); // returns [2]
myArray = pureAddNumber (3) (myArray);
console.log (myArray); // returns [2, 3]
複製程式碼
在陣列中,Push函式就是不純的,它會改變它所呼叫的陣列,因此會產生副作用。 push的返回值是一個數字索引。
另外,Concat接受陣列並將其與另一個陣列連線,從而產生一個沒有副作用的全新陣列。然後返回兩個陣列串聯後的新陣列。
純函式很重要,因為它們簡化了單元測試(沒有副作用,也不需要依賴注入),它們避免緊密耦合,並通過消除副作用,使應用程式更加簡潔。
我專門撰寫了一篇文章來討論純函式在程式設計中的最佳實踐:JavaScript Pure Functions for OOP developers
結語
理解函數語言程式設計並不能讓你成為更好的開發者,它會讓你成為一個更好的人。你可以通過lambda演算用啤酒來招待你的朋友,可以通過有趣的數學邏輯來糾正你的家人。
要在實踐中使用所有這些術語,請閱讀:8 steps to turn imperative JavaScript class to a functional declarative code
另外,要了解有關條件語句和條件表示式的更多資訊,請閱讀:How to replace switch and ternaries in functional JavaScript