1.函数柯里化
//函数的柯里化:复用重复参数的部分,可以使得其余不一致参数,基于重复参数所得到的函数进行调用
//常见场景:
// let baseFn = fn(1, 2);
// let res1 = baseFn(6);
// let res2 = baseFn(8);
// 1.返回一个函数(直到所有参数全部传递完毕,才会真正执行fn)
function curry(func) {
return function curried(...args) {
if (args.length >= func.length) {
return func.apply(this, args);
} else {
return function(...args2) {
return curried.apply(this, args.concat(args2));
}
}
};
}
function sum(a, b, c) {
return a + b + c;
}
let curriedSum = curry(sum);
alert( curriedSum(1, 2, 3) ); // 6,仍然可以被正常调用
alert( curriedSum(1)(2,3) ); // 6,对第一个参数的柯里化
alert( curriedSum(1)(2)(3) ); // 6,全柯里化
易混淆题目:对fn.toString进行重写
问题:add(1)(2) add(1)(3)(4)...实现无限极累加,实现累加器
// 累加器(fn.toString+闭包)
const add=(arg1)=>{
let args=[arg1]
const fn=arg2=>{
args.push(arg2);
return fn //自己返回自己,才能实现add的无限执行
}
fn.toString=function(){
return args.reduce((prev,item)=>prev+item,0)
}
return fn;
}
console.log(add(2)) //alert可以得到结果2
console.log(add(2)(1)) //alert可以得到结果3
2.函数编排compose
//如何实现函数编排:常见场景:一个函数的返回结果是另一个函数的参数
function TshirtNum(num) {
return num + 100;
}
function disCount(num) {
return num * 0.8;
}
function shoesNum(num) {
return num * 3;
}
function asyncNum(num) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(num * 0.8);
}, 1000);
});
}
function asyncShoesNum(num) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(num * 3);
}, 0);
});
}
//常规使用:若函数嵌套过多,则可读性很差
let discountNum = disCount(100);
let shoes = shoesNum(discountNum);
let tshirt = TshirtNum(discountNum);
console.log(tshirt);
/**
* compose的同步实现
* */
const compose = (fnArr) => (startNum) =>
fnArr.reduce((total, item) => item(total), startNum);
//分析:
// 1.compose返回的是一个函数,且接收一个初始值
//reduce以初始值为起点,每次item(total)执行所传递的参数都是上一次函数执行的结果
let price1 = compose([disCount, shoesNum]);
console.log(price1)
/**
* compose的异步实现
* */
const composeAsync = (fnArr) => (startNum) =>
fnArr.reduce((total, item) => {
console.log(total, item);
return total.then(item);
}, Promise.resolve(startNum));
let price = composeAsync([asyncNum, shoesNum]);
console.log("******", price(100));
price(100).then((res) => {
console.log("***", res); //一秒之后,打出结果
});
compose的特殊效果:koa-compose(应用考点)
题目:按照顺序执行
//洋葱形式的执行
//要求执行顺序由内到外,退出时再由外到内
function TshirtNum(num, next) {
console.log("starting TshirtNum");
next(num + 100);
console.log("end TshirtNum");
}
function disCount(num, next) {
console.log("starting disCount");
next(num * 0.8);
console.log("end disCount");
}
function shoesNum(num, next) {
console.log("starting shoesNum");
next(num * 3);
console.log("end shoesNum");
}
//要求:想要执行顺序依次为:
// starting TshirtNum
// starting disCount
// starting shoesNum
// end shoesNum
// end disCount
// end TshirtNum
按照以上要求,compose手写实现:
function compose(arr) {
return function (startNum) {
let result;
let dispatch = function (i, ctx) {
let fn;
if (i < arr.length) {
fn = arr[i];
}
console.log("*********", [fn], ctx);
if (i === arr.length) {
result = ctx;
return;
}
//注意:bind会返回一个函数
return fn(ctx, dispatch.bind(null, ++i));
};
dispatch(0, startNum); //初始执行
return result;
};
}
let composeFn = compose([TshirtNum, disCount, shoesNum]);
console.log("最终结果:", composeFn(100));
执行结果: