函数式编程——惰性链

概述

这是我读《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避免了难看的多条调用或者难看的嵌套调用,使代码变得非常清晰!!!

猜你喜欢

转载自www.cnblogs.com/yangzhou33/p/9185303.html
今日推荐