前几天去买菜,老爸说为啥称重的时候,老板一件一件往秤上放,嘴里念叨单价,最后就报总价了。是称了每种商品的价钱,最后心算的总价仍是机器统计的总价?我说确定是机器统计的,就是把数据暂时存起来,最后相加呗。这小功能二十年前就有了吧( ╯□╰ )?!javascript
随后我去淘宝搜索了一下,电子秤价格几十块到一两百,都有置零和累计功能。 java
那么累计功能不就是个最后统计求和吗,这让我想到了函数柯里化,最简单的理解就是一个函数接受参数,最开始不求值,而是到最后才求值(例如参数为空的时候)。咱们能够直接写个具备这个特征的求值函数,这个函数应该会用到闭包去暂存以前输入的参数,结合菜场算帐这个例子就很容易理解。typescript
/** * * @param fn input Function to be currified. when fn has no param?(you can define your call condition), fn would be really called. * otherwise, cache its args in closure. */
function currify(fn: Function) {
let args: any[] = [];
return function(arg?:any) { // 这就是咱们currify 以后的函数定义,在参数不为空的时候存起来,参数为空就call fn根据全部参数求值。
if (arguments.length === 0) {
console.log(`ready2call fn with args ${args}`);
return fn.call(this, args);
} else {
[].push.apply(args, arguments);
}
}
}
function sum(prices: number[]): number {
return prices.reduce((prev: number, cur: number) => {
return prev + cur;
}, 0);
}
let currifiedSum = currify(sum); // sum 求和函数就是fn,被currify以后新函数具备最后求值的特性
currifiedSum(10);
currifiedSum(20);
currifiedSum(40);
console.warn(currifiedSum());
复制代码
这个currify函数挺有意思的,实际上相似于装饰器,让新的currifiedSum 函数具备了最后求值的功能,这是sum函数原来不具备的特性。结合typescript的装饰器,其实能够写成更简洁的方式:设计模式
@currying()
sum(prices: number[]): number {
// 函数定义
}
复制代码
那么以前这个需求比较简单,就是参数为空统计求和。那实际的电子秤是在每类物品称量阶段接受两个参数,一个是物品单价(price),一个是物品重量(weight),计算当前物品的价钱。在某顾客全部物品称重结束时点击累计按钮,触发统计功能。闭包
那简单修改下,让现有的sum 函数具备这个功能吧。app
function extCurrify(fn: Function) {
let args: any[] = [];
return function(arg?: any, arg2?: any) {
if (arguments.length === 0) {
console.log(`ready2call fn with args ${args}`);
return fn.call(this, args);
}
if (arguments.length === 2) {
// if has weight & price
[].push.call(args, calcPrice.call(this, arguments[0], arguments[1]));
} else {
[].push.apply(args, arguments);
}
}
}
function calcPrice(input: number, price: number): number {
console.warn(`cur price: ${input * price}`);
return input * price;
}
let currifiedSum = extCurrify(sum);
currifiedSum(10, 2.2); // weight & price
currifiedSum(1, 30);
currifiedSum(2, 2);
console.warn(currifiedSum());
复制代码
这样加个条件,就能够支持每一个阶段再作个乘法,最后求和。虽然破坏了柯里化函数的通用性结构。 代码比较简单,可是我以为这个生活例子颇有趣,好理解,因此写下来。其中闭包、高阶函数的应用,能够达成装饰器的设计模式,在尽可能不破坏currify函数的通用性前提下,把逻辑代码单独出来为 sum,或者其余功能函数。函数