高阶函数
函数柯里化
一遍编程题引发的思考
实现 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)()); // 6console.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 )))}}
