最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

ecmascript 6 - piping functions in JavaScript - Stack Overflow

programmeradmin7浏览0评论

How can I have a JavaScript function let's say piper() which takes several functions as its arguments and it returns a new function that will pass its argument to the first function, then pass the result to the second, then pass the result of the second to the third, and so on, finally returning the output of the last function.

Something like piper(foo, fee, faa)(10, 20, 30) would be equivalent to calling faa(fee(foo(10,20,30))).

ps: It was a part of an interview, that I did few days ago.

How can I have a JavaScript function let's say piper() which takes several functions as its arguments and it returns a new function that will pass its argument to the first function, then pass the result to the second, then pass the result of the second to the third, and so on, finally returning the output of the last function.

Something like piper(foo, fee, faa)(10, 20, 30) would be equivalent to calling faa(fee(foo(10,20,30))).

ps: It was a part of an interview, that I did few days ago.

Share Improve this question edited Oct 12, 2016 at 20:25 Mike Cluck 32.5k13 gold badges83 silver badges94 bronze badges asked Oct 12, 2016 at 20:23 user84user84 8951 gold badge14 silver badges45 bronze badges 13
  • 1 Have you tried anything yourself? – Mike Cluck Commented Oct 12, 2016 at 20:24
  • ramdajs./docs/#pipe – Jared Smith Commented Oct 12, 2016 at 20:25
  • @MikeC I am used to see functions in js like this function ali( saberi,i) {saberi(i)}, not in this way.with 2 paranthesis – user84 Commented Oct 12, 2016 at 20:27
  • 1 @AliSaberi Remember: you can return functions from a function. See this question. – Mike Cluck Commented Oct 12, 2016 at 20:31
  • 1 Like a lot of interview questions, if you ever code like this you deserve to fail a code review. This is absolutely nuts. f(...)(...)(...) is not readable at all. As an academic exercise the hints are in your question: it "returns a new function". – tadman Commented Oct 12, 2016 at 20:33
 |  Show 8 more ments

7 Answers 7

Reset to default 10

For an arbritrary number of functions you could use this ES6 function:

function piper(...fs) {
    return (...args) => fs.reduce((args,f) => [f.apply(this,args)],args)[0];
}
// Example call:
var result = piper(Math.min, Math.abs, Math.sqrt)(16, -9, 0)
// Output result:
console.log(result);

The same in ES5 syntax:

function piper(/* functions */) {
    var fs = [].slice.apply(arguments);
    return function (/* arguments */) { 
        return fs.reduce(function (args,f) {
            return [f.apply(this,args)];
        }.bind(this), [].slice.apply(arguments))[0];
    }.bind(this);
}
// Example call:
var result = piper(Math.min, Math.abs, Math.sqrt)(16, -9, 0)
// Output result:
console.log(result);

Enjoy. Pure ES5 solution. Preserves this.

function piper(){
    var i = arguments.length,
        piped = arguments[ --i ];

    while( --i >= 0 ){
        piped = pipeTwo( arguments[ i ], piped );
    }

    return piped;
}

function pipeTwo( a, b ){
    return function(){
        return a.call( this, b.apply( this, arguments ) );
    }
}

Or, if you want the fancy solution.

function piperES6( ...args ){
    return args.reverse().reduce( pipeTwo );
}

Loops can be reversed depending on the desired direction.

Very similar to @trincot's answer (preserves context), but poses in the correct order and is marginally faster since it does not create intermediary arrays:

const piper = (...steps) => function(...arguments) {
  let value = steps[0].apply(this, arguments);
  for (let i = 1; i < steps.length; ++i) {
    value = steps[i].call(this, value);
  }
  return value;
};



// Usage:

let p = piper(
  x => x + 1,
  x => x * 2,
  x => x - 1
);

console.log(p(2)); // 5

Here is an alternative answer involving method chaining. I shall use ES6, though of course this can be transpiled to ES5. On benefit of this solution is that is has a very succinct TypeScript counterpart with perfect typeability.

class Pipe {
    constructor(value) {
        this.value = value;
    }
    then(f) {
        return new Pipe(f(this.value));
    }
}
    
const pipe = value => new Pipe(value);
    
// Example

const double = x => 2 * x;
    
pipe(42).then(double).then(console.log); // 84

const result = pipe(42).then(double).then(double).value;
console.log(result); // 168

A simple solution based on JS higher-order functions usage:

function pipe(...rest) {
  return x => rest.reduce((y, f) => f(y), x);
}

Usage:

pipe((a) => a + 1, (a) => a * 2)(3) // 8
pipe((a) => a + 1, (a) => a * 2)(2) // 2
function f(f1, f2, f3){

    return (args => f3(f2(f1(args))));

}

I think what you are trying to do is chaining.

var funct={
    total:0,
    add:function(a) {
        console.log(funct.total,funct.total+a);
        funct.total+=a;

        return funct;
    }
};


funct.add(5).add(6).add(9);
发布评论

评论列表(0)

  1. 暂无评论