简体   繁体   中英

Can you help me understand how piping functions in javascript work?

I am reading a book called Learning React, 2nd Edition . There's a section about function composition under functional programming section. The code snippet and explanation provided are not super clear to me. Here's the code snippet from the book - 在此处输入图像描述 在此处输入图像描述

Here's the above code in code snippet -

const both = compose(
  civilianHours,
  appendAMPM
):

both(new Date());

const compose = (...fns) => arg => 
  fns.reduce((compose, f) => f(composed), arg);

I don't understand what the author is trying to explain here. Here's the explanation provided from the book for this snippet.

The compose function is a higher-order function. It takes functions as arguments and returns a single value. compose takes in functions as arguments and returns a single function. In this implementation, the spread operator is used to turn those function arguments into an array called fns. A function is then returned that expects one argument, arg. When this function is invoked, the fns array is piped starting with the argument we want to send through the function. The argument becomes the initial value for compose, then each iteration of the reduced callback returns. Notice that the callback takes two arguments: composed and a function f. Each function is invoked with compose, which is the result of the previous function's output. Eventually, the last function will be invoked and the last result returned.

So can anyone explain to me how function piping works in javascript with some examples? It would be nice if someone could explain the above code snippet too. Especially what the arg is doing sitting over there.

Here's another code snippet for the same question -

const add2 = (x) => x + 2;
const subtract1 = (x) => x - 1;
const multiplyBy5 = (x) => x * 5;

const pipe = (...fns) => (val) => fns.reduce((prev, fn) => fn(prev), val);

const pipeResult = pipe(add2, subtract1, multiplyBy5)(5);

console.log(pipeResult); // = 30

It might be clearer if we use a loop rather than reduce ( reduce can be hard to read), and use the verbose form of the arrow function rather than the concise one:

const compose = (...fns) => {
    return (arg) => {
        let composed = arg;
        for (const fn of fns) {
            composed = fn(composed);
        }
        return composed;
    };
};

compose accepts a bunch of functions as discrete arguments, gathering them all up into an array with a rest parameter ( ...fns ). It returns a function that accepts a single parameter ( arg ). When you call that function, it loops through the functions in fns . The first function gets arg (which I've copied to composed above). The code takes the result of calling the first function to give to the next, then keeps the result of calling that to call the next, etc., eventually returning the last result when it runs out of functions.

In the both example, it's basically doing this:

let firstResult = civilianHours(new Date());
let composed = appendAMPM(firstResult);
// Or
let composed = appendAMPM(civilianHours(new Date()));

(except oddly the book's example doesn't use the return value of both .)

The "pipeline" concept comes from the fact that compose is basically laying out the functions it receives in a row, where each function passes its result to the next function, like a series of connected pipes that a liquid flows through:

arg −−−> add2 −−−> subtract1 −−−> multiplyBy5 −−−> result

Here's a live example of the math example at the end of the question, with some logging to help show what's going on:

 const compose = (...fns) => { console.log(`Creating function to do ${fns.map(fn => fn.name).join(" => ")}`); return (arg) => { let composed = arg; for (const fn of fns) { const msg = `${fn.name}(${composed})`; composed = fn(composed); console.log(`${msg} returns ${composed}`); } return composed; }; }; const add2 = (x) => x + 2; const subtract1 = (x) => x - 1; const multiplyBy5 = (x) => x * 5; const pipeResult = compose(add2, subtract1, multiplyBy5)(5); console.log(pipeResult); // = 30

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM