How to avoid multiple variable re-declarations on function outputs in JavaScript

前端 未结 6 1291
生来不讨喜
生来不讨喜 2021-01-24 16:37

Consider the following example

function doSomethingToAVariable(variable){
    return variable + 1
}

function doSomethingToAVariableASecondTime(variable){
    re         


        
相关标签:
6条回答
  • 2021-01-24 17:07

    Function composition to the rescue.
    Take a look at libraries for functional programming, like Ramda, or lodash-fp.

    here a plain JS snippet to compose functions:

    //the compose-method you find in your regular FP-libs
    var compose = (...funcs) => (value) => funcs.reduceRight((v,fn)=>fn(v), value);
    //or a function wich takes the functions in opposite order, 
    //wich might be more common to you
    var pipe = (...funcs) => (value) => funcs.reduce((v,fn)=>fn(v), value);
    

    compose is a direct mapping of the composition you try to build

    var composition = (value) => a(b(c(value)));
    var composition = compose(a, b, c);
    //it calls the functions from right to left
    

    pipe is more oriented on your known imperative style to process a value step by step

    var composition = function(value){
        value = c(value);
        value = b(value);
        value = a(value);
        return value;
    }
    //pipe the value through c, then through b, then through a
    var fn = pipe(c, b, a);
    //wich in the end does exactly the same as the code built by compose
    

    so back to your code:

    var composition = pipe(
        doSomethingToAVariable,
        doSomethingToAVariableASecondTime,
        doSomethingToAVariableLastly
    );
    //or
    var composition = compose(
        doSomethingToAVariableLastly,
        doSomethingToAVariableASecondTime,
        doSomethingToAVariable
    );
    
    //and run it
    var myVariable = composition(0);
    
    0 讨论(0)
  • 2021-01-24 17:07

    If you want to chain then you need to return the object instead which will contain the final value

    function variableOperations( initialValue )
    {
      this.value = initialValue;
      this.someOp1 = function(){ this.value += 1; return this; } 
      this.someOp2 = function(){ this.value += 2; return this; } 
    }
    
    var a = new variableOperations(1); //new object
    a.someOp1().someOp2();
    
    alert(a.value); //alerts 4
    
    0 讨论(0)
  • 2021-01-24 17:10

    In this case you're looking for what's called "function composition":

    var myVariable = doSomethingToAVariableLastly(doSomethingToAVariableASecondTime(doSomethingToAVariable(0)));
    

    but this is clearly not readable with such long function names.

    Promises are typically only useful for asynchronous operations, and whilst they'd work in this scenario, the result would be inefficient and would introduce async dependencies where none are needed:

    var promise = doSomethingToAVariable(0);
            .then(doSomethingToAVariableASecondTime);
            .then(doSomethingToAVariableLastly);
    

    since you can only access the final result from the end of the chain of .then callbacks:

    promise.then(function(myVariable) {
        // myVariable is now 6, and in scope
    }
    
    // but it's not in scope or usable here
    
    0 讨论(0)
  • 2021-01-24 17:16

    Why not take a look at a functional approach with Ramda?

    R.compose(
      doSomethingToAVariableLastly,
      doSomethingToAVariableASecondTime,  
      doSomethingToAVariable
    )(myVariable)
    
    0 讨论(0)
  • 2021-01-24 17:27

    If it's as simple as adding some things together how about a recursive method. A bit like using promises but without actually using them.

    function add(x) {
      return {
        done: () => x,
        add: (y) => add(x + y)
      }
    }
    
    let myVariable = 0;
    add(myVariable).add(1).add(2).add(3).done(); // 6
    

    DEMO

    0 讨论(0)
  • 2021-01-24 17:30

    In my humble opinion, your code is perfectly fine.

    But, you can do something like this if you really want to "chain" the calls. It is a bit less efficient though.

    function chainCalls(initVal, funcs){
      return funcs.reduce(function(val, f){
        return f(val);
      }, initVal || 0);
    }
    
    function doSomethingToAVariable(variable){
        return variable + 1
    }
    
    function doSomethingToAVariableASecondTime(variable){
        return variable + 2
    }
    
    function doSomethingToAVariableLastly(variable){
        return variable + 3
    }
    
    var myVariable = chainCalls(0, [doSomethingToAVariable,
                                    doSomethingToAVariableASecondTime,
                                    doSomethingToAVariableLastly]);
    
    document.write(myVariable);

    Another alternative is to create a reusable function chain like this.

    function functionChain(){
      var funcs = arguments;
      return function(value){
        return Array.prototype.reduce.call(funcs, function(value, f){
          return f(value);
        }, value);
      };
    }
    
    function doSomethingToAVariable(variable){
        return variable + 1
    }
    
    function doSomethingToAVariableASecondTime(variable){
        return variable + 2
    }
    
    function doSomethingToAVariableLastly(variable){
        return variable + 3
    }
    
    var myVariable = functionChain(
      doSomethingToAVariable,
      doSomethingToAVariableASecondTime,
      doSomethingToAVariableLastly
    )(0);
    
    document.write(myVariable);

    0 讨论(0)
提交回复
热议问题