# 高阶函数

# 函数柯里化

一遍编程题引发的思考

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

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

第一反应是柯里化

function add(a, b) {
  return a + b;
}
function curry(add) {
  let arr = [];
  return function reply() {
    let arg = [...arguments];
    arr = arr.concat(arg);
    if (arg.length == 0) {
      return arr.reduce((p, c) => (p = add(p, c)), 0);
    } else {
      return reply;
    }
  };
}

let sum = curry(add);

console.log(sum(1, 2, 3)()); // 6
console.log(sum(2, 3)(1)()); //12

显然 这一没有 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 )))
     }

}
Last Updated: 12/22/2022, 9:53:26 AM