重磅升級(jí)千峰2023java就業(yè)班-日出江花紅勝火
JS 函數(shù)式概念: 管道 和 組合
重磅升級(jí)千峰2023java就業(yè)班
download:https://www.51xuebc.com/thread-530-1-1.html
函數(shù)管道和組合是函數(shù)式編程中的概念,當(dāng)然也能夠在JavaScript中完成--由于它是一種多范式的編程言語(yǔ),讓我們快速深化理解這個(gè)概念。
這個(gè)概念就是依照一定的次第執(zhí)行多個(gè)函數(shù),并將一個(gè)函數(shù)的結(jié)果傳送給下一個(gè)函數(shù)。
你能夠像這樣做得很難看:
function1(function2(function3(initialArg)))
或者運(yùn)用函數(shù)組合:
compose(function3, function2, function1)(initialArg);
或功用管道:
pipe(function1, function2, function3)(initialArg);
簡(jiǎn)而言之,組合和管道簡(jiǎn)直是一樣的,獨(dú)一的區(qū)別是執(zhí)行次第;假如函數(shù)從左到右執(zhí)行,就是管道,另一方面,假如函數(shù)從右到左執(zhí)行,就叫組合。
一個(gè)更精確的定義是。"在函數(shù)式編程中,compose是將較小的單元(我們的函數(shù))組合成更復(fù)雜的東西(你猜對(duì)了,是另一個(gè)函數(shù))的機(jī)制"。
下面是一個(gè)管道函數(shù)的例子。
const pipe = (...functions) => (value) => {
return functions.reduce((currentValue, currentFunction) => {
return currentFunction(currentValue);
}, value);
};
讓我們來(lái)補(bǔ)充一些這方面的見(jiàn)解。
根底學(xué)問(wèn)
我們需求搜集N多的函數(shù)
同時(shí)選擇一個(gè)參數(shù)
以鏈?zhǔn)椒绞綀?zhí)行它們,將收到的參數(shù)傳送給將被執(zhí)行的第一個(gè)函數(shù)
調(diào)用下一個(gè)函數(shù),參加第一個(gè)函數(shù)的結(jié)果作為參數(shù)。
繼續(xù)對(duì)數(shù)組中的每個(gè)函數(shù)做同樣的操作。
/* destructuring to unpack our array of functions into functions */
const pipe = (...functions) =>
/* value is the received argument */
(value) => {
/* reduce helps by doing the iteration over all functions stacking the result */
return functions.reduce((currentValue, currentFunction) => {
/* we return the current function, sending the current value to it */
return currentFunction(currentValue);
}, value);
};
我們?cè)?jīng)曉得,箭頭函數(shù)假如只返回一條語(yǔ)句,就不需求括號(hào),也不需求返回標(biāo)簽,所以我們能夠經(jīng)過(guò)這樣寫(xiě)來(lái)減少鍵盤(pán)的點(diǎn)擊次數(shù)。
const pipe = (...functions) => (input) => functions.reduce((chain, func) => func(chain), input);
如何運(yùn)用
const pipe = (...fns) => (input) => fns.reduce((chain, func) => func(chain), input);
const sum = (...args) => args.flat(1).reduce((x, y) => x + y);
const square = (val) => val*val;
pipe(sum, square)([3, 5]); // 64
記住,第一個(gè)函數(shù)是左邊的那個(gè)(Pipe),所以3+5=8,8的平方是64。我們的測(cè)試很順利,一切似乎都很正常,但假如要用鏈?zhǔn)?async 函數(shù)呢?
異步函數(shù)上的管道
我在這方面的一個(gè)用例是有一個(gè)中間件來(lái)處置客戶端和網(wǎng)關(guān)之間的懇求,過(guò)程總是相同的(做懇求,錯(cuò)誤處置,選擇響應(yīng)中的數(shù)據(jù),處置響應(yīng)以烹制一些數(shù)據(jù),等等等等),所以讓它看起來(lái)像一個(gè)魅力。
export default async function handler(req, res) {
switch (req.method) {
case 'GET':
return pipeAsync(provide, parseData, answer)(req.headers);
/*
...
*/
讓我們看看如何在Javascript和Typescript中處置異步函數(shù)管道。
JS版
export const pipeAsync =
(...fns) =>
(input) =>
fns.reduce((chain, func) => chain.then(func), Promise.resolve(input));
添加了JSDoc類型,使其更容易了解(我猜)。
/**
* Applies Function piping to an array of async Functions.
* @param {Promise<Function>[]} fns
* @returns {Function}
*/
export const pipeAsync =
(...fns) =>
(/** @type {any} */ input) =>
fns.reduce((/** @type {Promise<Function>} */ chain, /** @type {Function | Promise<Function> | any} */ func) => chain.then(func), Promise.resolve(input));
TS版
export const pipeAsync: any =
(...fns: Promise<Function>[]) =>
(input: any) =>
fns.reduce((chain: Promise<Function>, func: Function | Promise<Function> | any) => chain.then(func), Promise.resolve(input));
這樣一來(lái),它對(duì)異步和非異步函數(shù)都有效,所以它比上面的例子更勝一籌。
你可能想曉得函數(shù)的組成是什么,所以讓我們來(lái)看看。
函數(shù)組合
假如你喜歡從右到左調(diào)用這些函數(shù),你只需求將reduce改為redureRight,就能夠了。讓我們看看用函數(shù)組成的異步方式。
export const composeAsync =
(...fns) =>
(input) =>
fns.reduceRight((chain, func) => chain.then(func), Promise.resolve(input));
回到上面的例子,讓我們復(fù)制同樣的內(nèi)容,但要有構(gòu)圖。
如何運(yùn)用
const compose = (...fns) => (input) => fns.reduceRight((chain, func) => func(chain), input);
const sum = (...args) => args.flat(1).reduce((x, y) => x + y);
const square = (val) => val*val;
compose(square, sum)([3, 5]); // 64
請(qǐng)留意,我們顛倒了函數(shù)的次第,以堅(jiān)持與帖子頂部的例子分歧。
如今,sum(位于最右邊的位置)將被首先調(diào)用,因而3+5=8,然后8的平方是64。