什麼是Pointfree風格?中譯過來是無參數風格或者無值風格,意即爲在編寫程序時不關注具體數據以及對象,而只關注的是運算過程。編程
下文將用簡單的例子帶你們瞭解Pointfree風格~函數式編程
"告訴計算機該怎麼作,詳細的執行步驟"函數
考慮如下需求:小A去水果店去買水果,他想知道水果店裏有存貨而且最貴的水果名稱是什麼?工具
const fruits = [
{ name: 'Apple', price: 4, stock: true },
{ name: 'Peach', price: 14, stock: true },
{ name: 'Grape', price: 30, stock: false },
{ name: 'Pear', price: 6, stock: true },
];
複製代碼
咱們常見的實現方式通常以下:post
// Ex 1
const fruitsHaveStock = fruits.filter(fruit => fruit.stock);
const sortedDescFruits = fruitsHaveStock.sort((a, b) => b.price - a.price);
const mostExpensiveFruitName = sortedDescFruits[0].name;
console.log(mostExpensiveFruitName); // Peach
複製代碼
這個是很明顯的命令式編程,由於大腦會習慣線性的去理解事物,因此咱們天然而然的羅列了這個需求的實現步驟,從而實現了上述的需求。可是這樣的代碼缺點以下:單元測試
fruits.filter(fruit => fruit.stock);
中的fruit
參數、fruitsHaveStock
、sortedDescFruits
這些都是Point,換句話說,咱們的程序關注了被操做的數據!"告訴計算機作什麼,咱們想要什麼"學習
上述代碼用聲明式的風格重寫一下~測試
// Ex 2
const filter = predicate => list => list.filter(predicate);
const propEq = (key, value) => target => target[key] === value;
const compose = (...funcs) => result => [...funcs]
.reverse()
.reduce((result, fn) => fn(result), result);
const sort = func => list => list.sort(func);
const prop = key => target => target[key];
const head = list => list.slice(0, 1).pop();
function getHaveStock(list) {
return filter(propEq('stock', true))(list);
}
function sortByPriceDesc(list) {
return sort((a, b) => b.price - a.price)(list);
}
function getName(target) {
return prop('name')(target);
}
function getMostExpensiveFruitName(list) {
return compose(
getName, head, sortByPriceDesc, getHaveStock
)(list);
}
console.log(getMostExpensiveFruitName(fruits)); // Peach
複製代碼
同窗們對比Ex 1和Ex 2代碼,能夠發現兩點:優化
filter
、propEq
、compose
等等(備註,關於compose
方法若是不懂的話,能夠閱讀我以前寫的一篇文章參考哦:Compose & Pipe - 函數式編程)(●´∀`●)ノui
可是問題來了,細心的同窗應該發現了一個問題,雖說咱們改爲了聲明式編程的風格,可是咱們仍是關注了要處理的數據自己(也就是值),什麼意思?
好比這個函數:
function getHaveStock(list) {
return filter(propEq('stock', true))(list);
}
複製代碼
由於咱們只想關心怎麼運算操做!list參數對於函數自己實現來講,徹底屬於多餘,且也不須要關注的。
因而咱們能夠改寫以下:
const getHaveStock = filter(propEq('stock', true));
複製代碼
其他sortByPriceDesc
, getName
, getMostExpensiveFruitName
同理優化。因而就達到了咱們說的 Pointfree 啦!(由於咱們幹掉了point -> list參數)
固然,說不定有些同窗發發牢騷了:「代碼好像變得更長了...並且還寫了一大堆莫名其妙的工具方法,我纔不想這麼幹呢!」
這位同窗說的有道理!請繼續往下看~
一款實用的,專門爲函數式編程風格而設計的JavaScript函數式編程庫
若是決心瞭解JavaScript函數式編程,而且想要用Pointfree風格優化一下代碼,那麼ramda是值得學習的!它幫咱們省掉了上述Ex 2寫的大量工具函數。 官網貼上:ramda
因此,咱們使用ramda改寫一下~
// Ex 3
const { filter, propEq, sort, prop, compose, head } = require('ramda');
const haveStock = propEq('stock', true);
const getHaveStock = filter(haveStock);
const sortByPriceDesc = sort((a, b) => b.price - a.price);
const getName = prop('name');
const getMostExpensiveFruitName = compose(
getName, head, sortByPriceDesc, getHaveStock
);
console.log(getMostExpensiveFruitName(fruits)); // Peach
複製代碼
上述代碼的優勢體如今如下三方面:
備註:ramda其實能夠大體理解爲函數式風格的lodash工具庫,它和lodash的區別主要在於兩點:
Pointfree風格的確須要必定的時間才能習慣,可是也不能一律而論把全部函數的參數都移除掉,具體狀況仍是須要具體分析。Pointfree風格雖然有時候也會形成一些困惑,但的確讓代碼更加簡潔和易於理解了。
固然,若是願意花點時間去練習和習慣Pointfree風格,相信仍是會很值得的。