函数柯里化
函数柯里化的定义
把一个接受多个参数的函数转化成一个接收单个参数的函数,并且返回一个接收剩余参数而且返回结果的新函数
举例说明:
function sum (a + b) {
return a + b
}
// 将sum函数柯里化
function curryingSum (a) {
return function (b) {
return a + b
}
}
const s = curryingSum(1)
s(2) // 3
柯里化的好处
- 参数复用
// 正则判断
function isPhoneNumber (regexp, number) {
return regexp.test(number)
}
// 使用
isPhoneNumber(/\d{11}/, '34324323d')
isPhoneNumber(/\d{11}/, '3432fdsaf4323d')
// 每次都要写两个参数,比较繁琐,可以采用柯里化修改
function curryingIsPhoneNumber (regexp) {
return function (number) {
return regexp.test(number)
}
}
const isPhoneNumber1 = curryingIsPhoneNumber(/\d{11}/)
isPhoneNumber1('2132434')
isPhoneNumber1('2132dfadsfadsf434')
- 提前判断
function addEvent (element, event, handler) {
if (document.addEventListener) { // 每次调用这个方法时都需要做一次判断
if (element && event && handler) {
element.addEventListener(event, handler)
}
} else {
if (element && event && handler) {
element.attachEvent('on' + event, handler);
}
}
}
// 柯里化函数
function curryingAddEvent () {
if (document.addEventListener) {
return function () {
if (element && event && handler) {
element.addEventListener(event, handler)
}
}
} else {
return function () {
if (element && event && handler) {
element.attachEvent('on' + event, handler);
}
}
}
}
const addEvent1 = curryingAddEvent()
- 延迟函数执行
// 像我们js中经常使用的bind,实现的机制就是Currying.
Function.prototype.bind = function (context) {
const args = Array.prototype.slice.call(arguments, 1)
const _self = this
return function () {
args.push(Array.prototype.slice.call(arguments))
return _self.apply(context, args)
}
}
currying封装函数
前面讲解了柯里化的用处,但是存在一个问题,我们不可能对每个函数进行修改让其柯里化
但是我们可以封装一个函数来对现有的函数进行柯里化
// 封装函数
function processCurrying (fn) {
const args = Array.prototype.slice.call(arguments, 1)
return function () {
const _args = Array.prototype.slice.call(arguments)
const allArgs = args.concat(_args) // 外层的和内层的参数融合成为一个实参带到fn中进行执行
return fn.apply(this, allArgs)
}
}
// 使用
function sum (a, b) {
console.log(a, b)
return a + b
}
const curryingSum = processCurrying(sum, 1)
curryingSum(2) // 3
上面的例子并不支持链式调用,比如 curryingSum(2)(3)(13, 2)
因此对上面的例子做一个递归的处理,来支持链式调用
function processCurrying (fn, args) {
const allArgs = args || []
const len = fn.length // Function.prototype.length 返回函数的形参个数
const _this = this
return function () {
const _args = Array.prototype.slice.call(arguments)
Array.prototype.push.call(allArgs, _args)
if (allArgs.length < len) { // 传递的参数并未达到形参个数将继续收集参数
return processCurrying.call(_this, fn, allArgs)
}
return fn.apply(this, allArgs)
}
}
// 使用
function sum (a, b) {
console.log(a, b)
return a + b
}
const curryingSum = processCurrying(sum)
curryingSum(2)(2)(2)(2) // 8