zoukankan      html  css  js  c++  java
  • 函数式编程——惰性链

    概述

    这是我读《javascript函数式编程》时,对链式编程的总结与思考,供以后开发时参考,相信对其他人也有用。

    chain

    在jquery和underscore里面,它们的内建对象$和_的方法通常会返回一个this,然后就实现了链式调用,这种调用非常方便。

    惰性链

    惰性就是延迟执行的意思,在编程的世界里,惰性XX听起来非常高大上,但是实现起来也许非常简单。我下面的代码就实现了一个惰性链:

    function lazyChain(fn) {
      var calls = [];
      return {
        invoke: function(funcStr, ...args){
          calls.push(function(target) {
            if(target === undefined) return fn[funcStr](...args);
            return fn[funcStr](target, ...args);
          });
          return this;
        },
        force: function() {
          return calls.reduce((accu, curFunc) => {
            if(accu === undefined) return curFunc();
            return curFunc(accu);
          }, undefined);
        }
      };
    }
    

    有以下几点需要说明:

    1. 使用了es6的...args来取剩余参数。
    2. 使用了array函数的reduce方法。
    3. 主要原理是,在使用invoke调用函数时,实际上没有调用,而是把函数储存在calls这个数组里面,等到执行force方法的时候,再一个个地调用函数。

    使用方法如下:

    函数无参数的情形:

    const fn1 = {
      hello: function() {
        console.log('hello');
      },
      mark1: function() {
        console.log(',');
      },
      world: function() {
        console.log('world');
      },
      mark2: function() {
        console.log('!');
      }
    };
    
    //此时没有任何输出,因为是惰性的。
    const words = lazyChain(fn1).invoke('hello').invoke('mark1').invoke('world').invoke('mark2');
    
    //此时输出:hello , world !
    words.force();
    

    函数有参数的情形:

    const fn2 = {
      add: function(a,b) {
        return a+b;
      },
      minus: function(a,b) {
        return a-b;
      },
      multiply: function(a,b) {
        return a*b;
      },
      divide: function(a,b) {
        return a/b;
      }
    };
    
    lazyChain(fn).invoke('add', 3, 4).invoke('minus', 2).invoke('multiply', 2).invoke('divide', 4).force(); //相当于(3+4-2)*2/4
    

    chain链的改进

    无论是juqery还是underscore里面的链式调用,调用的方法必须是jq对象或者underscore对象拥有的方法,那么如果我们想要调用它所没有的方法,应该怎么优化呢?

    我们可以类似上面那样,把方法传入一个数组里面,然后最后用force函数执行,代码如下:

    function optiChain() {
      var calls = [];
      return {
        invoke: function(func, ...args){
          calls.push(function(target) {
            if(target === undefined) return func(...args);
            return func(target, ...args);
          });
          return this;
        },
        force: function() {
          return calls.reduce((accu, curFunc) => {
            if(accu === undefined) return curFunc();
            return curFunc(accu);
          }, undefined);
        }
      };
    }
    

    使用方法如下:

    函数无参数的情形:

    function hello() {
        console.log('hello');
    }
    
    function mark1() {
        console.log(',');
    }
    
    function world() {
        console.log('world');
    }
    
    function mark2() {
        console.log('!');
    }
    
    //此时输出:hello , world !
    optiChain().invoke(hello).invoke(mark1).invoke(world).invoke(mark2).force();
    
    //如果不用optiChain则需要这么写
    hello();
    mark1();
    world();
    mark2();
    

    函数有参数的情形:

    function add(a, b) {
        return a + b;
    }
    
    function minus(a, b) {
        return a - b;
    }
    
    function multiply(a, b) {
        return a * b;
    }
    
    function divide(a, b) {
        return a / b;
    }
    
    //相当于(3+4-2)*2/4
    optiChain().invoke(add, 3, 4).invoke(minus, 2).invoke(multiply, 2).invoke(divide, 4).force();
    
    //如果不用optiChain则需要这么写
    divide(multiply(minus(add(3, 4), 2), 2), 4);
    

    可以看到,使用optiChain避免了难看的多条调用或者难看的嵌套调用,使代码变得非常清晰!!!

  • 相关阅读:
    OpenIOC
    网站舆情监测
    乌云的背后是阳光
    2014 十大工具
    NetFlow网络流量监测技术的应用和设计(转载)
    免费工具
    Oracle RAC环境下怎样更新patch(Rolling Patch)
    Answer's Question about pointer
    cocos2d-x 3.0 final 移植 android
    ReactNavtive框架教程(3)
  • 原文地址:https://www.cnblogs.com/yangzhou33/p/9185303.html
Copyright © 2011-2022 走看看