【问题标题】:Understanding how to implement lodash's _.flowRight in vanilla JavaScript了解如何在 vanilla JavaScript 中实现 lodash 的 _.flowRight
【发布时间】:2017-12-02 14:48:58
【问题描述】:

在学校,我们的任务是构建 lodash method flowRight! 的实现

在它提到的规范中:

接受任意数量的函数并返回一个新函数 使用它的参数并从右到左调用提供的函数 (最后到第一个)。每个函数的参数(第一个函数除外)是 由其右侧函数的返回值决定。通话 到 flowRight 返回的函数计算返回值 最左边的函数。

这是他们给出的一个例子:

e.g.

var sayHello = function (name) {
    return 'Hello, ' + name;
},

addExclamation = function (s) {
    return s + '!';
},

smallTalk = function (s) {
    return s + ' Nice weather we are having, eh?';
};

var greetEnthusiastically = flowRight(addExclamation, sayHello);

greetEnthusiastically('Antonio');
// --> returns 'Hello, Antonio!'
//(sayHello is called with 'Antonio', 
//  addExclamation is called with 'Hello, Antonio')

我觉得我理解了这个示例所演示的静态示例中发生了什么。

function (func1, func2) {
    return function(value) {
        return func1(func2(value));
    }
}

我想我很难把我的大脑围绕在一个循环中,我认为你会需要它。这是我目前的实现。

var flowRight = function (...args) {
    var Func;
    for(var i = args.length - 2; 0 > i; i--) {
        function Func(value) {
            return args[i](args[i + 1](value));
        }
    }
    return Func;
};

任何帮助将不胜感激!

【问题讨论】:

    标签: javascript recursion closures lodash


    【解决方案1】:

    不需要循环。如果允许,这将使用 ES6。

    这使用spreadrestreduce

    const flowRight = (...functions) => functions.reduce((a, c) => (...args) => a(c(...args)));
    

    以下示例

    var sayHello = function (name) {
      return 'Hello, ' + name;
     },
    
    addExclamation = function (s) {
      return s + '!';
    },
    
    smallTalk = function (s) {
      return s + ' Nice weather we are having, eh?';
    }
    
    const flowRight = (...functions) => functions.reduce((a, c) => (...args) => a(c(...args)))
    
    var greetEnthusiastically = flowRight(smallTalk, addExclamation, sayHello)
    
    console.log(greetEnthusiastically('Antonio'));

    【讨论】:

    • reduceRight 简化了事情,因为它不需要中介(...args) =>
    【解决方案2】:

    要从右向左流动,您可以使用...spread.reduceRight(x, y)

    我已经对下面的代码进行了注释,试图解释这一切是如何协同工作的。

    const sayHello = function (name) {
      return 'Hello, ' + name;
     };
    
    const addExclamation = function (s) {
      return s + '!';
    };
    
    const smallTalk = function (s) {
      return s + ' Nice weather we are having, eh?';
    }
    
    // function that takes functions and then
    // returns a function that takes  a value to apply to those functions in reverse
    const flowRight = (...fns) => val => fns.reduceRight((val, fn) => {
      // return the function and pass in the seed value or the value of the pervious fn.
      // You can think of it like the following.
      // 1st pass: sayHello(value) -> "Hello, " + value;
      // 2nd pass: addExclamation("Hello,  $value") -> "Hello,  $value" + "!";
      // 3rd pass: smallTalk("Hello,  $value!") -> "Hello,  $value!" + ' Nice weather we are having, eh?'
      // ... and so on, the reducer will keep calling the next fn with the previously returned value
      return fn(val)
    // seed the reducer with the value passed in
    }, val);
    
    var greetEnthusiastically = flowRight(smallTalk, addExclamation, sayHello);
    
    console.log(greetEnthusiastically('Antonio'));

    【讨论】:

      【解决方案3】:

      从右到左的构图

      const flowRight = (f, ...more) => x =>
        f == null ? x : f(flowRight(...more)(x))
      
      const upper = s =>
        s.toUpperCase()
      
      const greeting = s =>
        `Hello, ${s}`
      
      const addQuotes = s =>
        `"${s}"`
      
      const sayHello =
        flowRight(addQuotes, greeting, upper)
      
      console.log(sayHello("world"))
      // "Hello, WORLD"

      从左到右的构图

      const flowLeft = (f, ...more) => x =>
        f == null ? x : flowLeft(...more)(f(x))
      
      const upper = s =>
        s.toUpperCase()
      
      const greeting = s =>
        `Hello, ${s}`
      
      const addQuotes = s =>
        `"${s}"`
      
      const sayHello =
        flowLeft(addQuotes, greeting, upper)
      
      console.log(sayHello("world"))
      // HELLO, "WORLD"

      使用 reduceRight

      我们可以使用reduceRight 轻松实现flowRight -

      const flowRight = (...fs) => init =>
        fs.reduceRight((x, f) => f(x), init)
      
      const upper = s =>
        s.toUpperCase()
      
      const greeting = s =>
        `Hello, ${s}`
      
      const addQuotes = s =>
        `"${s}"`
      
      const sayHello =
        flowRight(addQuotes, greeting, upper)
      
      console.log(sayHello("world"))
      // "Hello, WORLD"

      使用reduce

      或者我们可以使用reduce 轻松实现flowRight -

      const flowLeft = (...fs) => init =>
        fs.reduce((x, f) => f(x), init)
      
      const upper = s =>
        s.toUpperCase()
      
      const greeting = s =>
        `Hello, ${s}`
      
      const addQuotes = s =>
        `"${s}"`
      
      const sayHello =
        flowLeft(addQuotes, greeting, upper)
      
      console.log(sayHello("world"))
      // HELLO, "WORLD"

      【讨论】:

        【解决方案4】:

        下面编写的函数的想法是返回一个函数,该函数将遍历函数列表并存储每次调用的结果并在最后返回。

        function flowRight(...args) {
            return function (initial) {
                let value = initial;
        
                for (let i = args.length - 1; i >= 0; i--) {
                    value = args[i](value);
                }
        
                return value;   
            };
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-03-11
          • 2018-07-17
          • 2019-07-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多