高阶函数

函数柯里化

一遍编程题引发的思考

实现 sum 函数使得下面输出结果一致

sum(1,2,3).sumOf()
sum(2,3)(1).sumOf()
sum(2)(1)(3).sumOf()

第一反应是柯里化函数

显然 这一没有 sumof 实现 也完全复用了

防抖和节流

强调一下它们的区别:

  • 节流是让事件处理函数隔一个指定毫秒再触发
  • 防抖则忽略中间的操作,只响应用户最后一次操作

函数拦截器

对废弃 API 进行提示增加

一个小细节,定义notice = once(console.warn),用notice输出,这样的话,调用相同的函数只会在控制台显示一遍警告,就避免了输出太多重复的信息。

function deprecate(fn, oldApi, newApi) {
  const message = `The ${oldApi} is deprecated.
Please use the ${newApi} instead.`;
  const notice = once(console.warn);
 
  return function(...args) {
    notice(message);
    return fn.apply(this, args);
  }
}

WEB 拦截器

function intercept(fn, {beforeCall = null, afterCall = null}) {
  return function (...args) {
    if(!beforeCall || beforeCall.call(this, args) !== false) {
      // 如果beforeCall返回false,不执行后续函数
      const ret = fn.apply(this, args);
      if(afterCall) return afterCall.call(this, ret);
      return ret;
    }
  };
}

axios 请求队列拦截器的实现

高阶函数的范式

function HOF0(fn) {
  return function(...args) {
    return fn.apply(this, args);
  }
}

HOF0是高阶函数的等价范式,或者说,HOF0修饰的函数功能和原函数fn的功能完全相同。因为被修饰后的函数就只是采用调用的this上下文和参数来调用fn,并将结果返回。也就是说,执行它和直接执行fn完全没区别。

compose

高阶函数可以任意组合,形成更强大的功能。

另外,像这样fn1(fn2(fn3(args…)))嵌套的写法,我们也可以用高阶函数改变成更加友好的形式: 也就是 compose

redux 版本(同步函数)

function f1(arg) {
  console.log("f1", arg);
  return arg;
}
function f2(arg) {
  console.log("f2", arg);
  return arg;
}
function f3(arg) {
  console.log("f3", arg);
  return arg;
}
 
const res = f1(f2(f3("omg")));
console.log("res", res); //sy-log
// f3 omg
// f2 omg
// f1 omg
// res omg

优化写法

function compose(...funcs) {
  if (!funcs.length) {
    return (arg) => arg;
  }
  return funcs.reduce((a, b) => (...args) => a(b(...args)));
}
 
compose(f1, f2, f3)("omg");
// f3 omg
// f2 omg
// f1 omg

koa 版本(异步中间件)

例子

function compose(middlewares){
     return () = >{
 
     }
}
 
async function fn1(next) {
    console.log("fn1");
    await next();
    console.log("end fn1");
}
 
async function fn2(next) {
    console.log("fn2");
    await delay();
    await next();
    console.log("end fn2");
}
 
function fn3(next) {
    console.log("fn3");
}
 
function delay() {
    return new Promise((reslove, reject) => {
        setTimeout(() => {
            reslove();
        }, 2000);
    });
}
 
 
const middlewares = [fn1, fn2, fn3];
const finalFn = compose(middlewares);
finalFn();

compose 实现

  • compose 接受一个 函数数组
  • 返回一个 具有一个 next 函数参数的 函数
  • 用 Promise 包装,
  • 考虑边界条件
function compose(middlewares){
     return () = >{
         dispatch(0)
     }
     function  dispatch(i){
         let fn = middlewares[i]
         if(!fn) return Promise.resolve()
         return fn(()=> Promise.resolve(dispatch(i +1 )))
     }
 
}