函数柯里化
基本概念
柯里化(Currying)又称部分求值,一个柯里化的函数首先会接收一些参数,接收了这些参数后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来。待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值。
柯里化是一种函数的转换,它是指将一个函数从可调用的 f(a, b, c) 转换为可调用的 f(a)(b)(c)或者f(a, b)(c)或者f(a)(b, c)
如果一个函数有多个参数,我们可以根据参数的个数,转化成n个函数
举个栗子
function fn (a, b, c) {
}
fn(1)(2)(3) // 典型的函数柯里化
// 或者
fn(1)(2, 3) // 也属于函数柯里化,但具体叫做偏函数,每次调用函数的参数个数可以不是一个
具体实践
- 在开发中,会经常封装一些类型判断函数用于日常使用,利用函数柯里化我们可以封装更加高效便捷的公共方法。
function isType(val, type) {
return Object.prototype.toString.call(val) === `[Object ${type}]` // 举个例子
}
isType('abc', 'String'); // 判断abc是否为string类型
isType(123, 'Number'); // 判断123是否为number类型
isType(true, 'Boolean'); // 判断true是否boolean类型
// 打印结果
true
true
true
- 我们会发现每次都需要传入类型来判断,会变得非常繁琐,于是我们利用函数柯里化来进行改写。
function isType(type) {
return function (val) {
return Object.prototype.toString.call(val) === `[Object ${type}]`;
}
}
const isString = isType('String');
const isNumber = isType('Number');
const isBoolean = isType('Boolean');
console.log(isString('1231')) // true
console.log(isNumber(1231)) // true
console.log(isBoolean(1231)) // false
- 经过改写之后,已经非常接近我们日常封装的方法了,但是我们会发现,每次做函数柯里化时,都需要重新写一个新的isType高阶函数返回一个函数进行逻辑运算,于是乎我们需要一个通用的柯里化函数,可以根据我们的参数个数生成N个函数提供调用。
function sum(a, b, c, d) {
return a + b + c + d;
}
// 通用柯里化函数
function curring(fn) {
// 我们需要统计每次传入的个数,是否等于fn(sum)的参数总个数,如果等于总个数,就直接调用fn(sum)
let args = []; // 记录参数的总个数
const innerFn = (arr = []) => { // 该参数为每次调用的个数
// 每次调用,获取到新的参数,合并参数总个数
args.push(...arr);
return args.length >= fn.length ? fn(...args) : (...args) => innerFn(args)
}
return innerFn();
}
const fn = curring(sum);
const fn1 = fn(1);
const fn2 = fn1(2, 3);
const fn3 = fn2(4);
console.log(fn3) // 10
- 利用通用柯里化函数,回到刚刚的例子
// 通用柯里化函数
function curring(fn) {
// 我们需要统计每次传入的个数,是否等于fn(sum)的参数总个数,如果等于总个数,就直接调用fn(sum)
let args = []; // 记录参数的总个数
const innerFn = (arr = []) => { // 该参数为每次调用的个数
// 每次调用,获取到新的参数,合并参数总个数
args.push(...arr);
return args.length >= fn.length ? fn(...args) : (...args) => innerFn(args)
}
return innerFn();
}
function isType(val, type) {
return Object.prototype.toString.call(val) === `[Object ${type}]` // 举个例子
}
const isString = curring(isType)('String');
const isNumber = curring(isType)('Number');
const isBoolean = curring(isType)('Boolean');
// 打印结果
console.log(isString('123123')) // true
console.log(isNumber(12312)) // true
console.log(isNumber(12312)) // false