原文地址javascript
做者:Martin Novákjava
讓咱們談談什麼是:lambdas(匿名函數)、 first-class functions(頭等函數)、higher-order functions(高階函數)、unary functions(一元函數)、currying(柯里化 )和pure functions(純函數)。es6
若是您不清楚命令式和聲明式編程之間的區別,能夠看個人文章: Imperative versus declarative code… what’s the difference? express
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 type 意味着,該類型能夠用做變量的值。在JavaScript中一個字符串是頭等類型,一個函數也是頭等類型。因此函數能夠接受其餘函數做爲參數,並返回函數做爲返回值。bash
在綁定事件監聽器時,函數做爲first-class被使用:函數式編程
const handler = () => console.log ('I am function');
document.addEventListener ('click', handler);
複製代碼
高階函數是一個接受其餘函數做爲參數或將函數做爲返回值返回的函數。 __First-order function(一階函數)__是一個函數,它不接受其餘函數做爲參數,而且不返回函數做爲其返回值。函數
const firstOrder = () => console.log ('First order strikes back!');
const higherOrder = whoStrikesBack => whoStrikesBack ();
higherOrder (firstOrder);
複製代碼
該術語涉及一個函數接受一些參數的元數。一元函數(i.e. monadic)是一個只接受一個參數的函數。oop
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(柯里化)是一個帶有多個參數的函數並將其轉換爲函數序列的過程,每一個函數只有一個參數。
一個有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。它可能會讓人習慣,可是我如今寫的全部函數都歸功於柯里化。
純函數是一種其返回值僅由其參數決定,沒有任何反作用的函數。
這意味着若是你在整個應用程序中的不一樣的一百個地放調用一個純函數相同的參數一百次,該函數始終返回相同的值。純函數不會更改或讀取外部狀態。
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