柯里化概念
利用闭包特点,实现参数复用,把多参数函数变成一系列单参数函数
实现方式
简单 手写柯里化
前提:确定函数参数个数;只允许柯里化方式调用
//封装公用方法 传入函数
function curry(f) {
return function (a) {
return function (b) {
return f(a, b)
}
}
}
function sum(a, b) {
return a + b
}
//单独使用 传入参数
function currySum(a) {
return function (b) {
return a + b
}
}
console.log(curry(sum)(1)(2)) //3
console.log(currySum(1)(2)) //3
高级 手写柯里化
前提:不确定函数参数;可以正常调用也可以柯里化方式调用,也可以偏函数(pratial)方式调用
重点步骤:
- apply改变
this
指向 - 柯里化式方法调用:递归
function curry(f) {
return function curried(...args) {
console.log(args)
//f.length 形参格式
//判断是正常调用 还是柯里化方式调用
if (args.length >= f.length) {
console.log(args)
console.log(f)
return f.apply(f, args)
} else {
return function (...args2) {
return curried.apply(this, args.concat(args2))
}
}
}
}
function sum(a, b) {
return a + b
}
sum = curry(sum)
//正常调用
console.log(sum(1, 2)) //3
// //柯里化
console.log(sum(1)(2)) //3
// //偏函数
let sum1 = sum(1)
console.log(sum1(2)) //3
lodash
前提:类高级手写柯里化
function sum(a, b) {
return a + b
}
sum = _.curry(sum)
//正常调用
console.log(sum(1, 2)) //3
//柯里化
console.log(sum(1)(2)) //3
//偏函数
let sum1 = sum(1)
console.log(sum1(2)) //3
好处
- 参数复用,可以减少传递部分不变参数
//九九乘法表
function haskell(a, b) {
return a * b
}
sum = _.curry(haskell)
//偏函数 第一个值固定
let sum1 = sum(9)
console.log(sum1(1)) //9
console.log(sum1(2)) //18
- 延迟执行(手写
bind
)
function win() {
return this
}
Function.prototype.bindFn = function (thisA) {
if (typeof this !== 'function') {
throw new Error(this + 'is not function')
}
if (thisA === null || typeof thisA === 'undefined') {
thisA = win()
}
thisA = new Object(thisA)
thisA['_fn'] = this
let a = [...arguments].slice(1)
return function () {
var res = thisA['_fn'](...a)
delete thisA['_fn']
return res
}
}
//测试
function print(a, b) {
console.log(this, a, b)
}
print.bindFn(null, 1, 2)() //window 1 2
缺点
- 函数嵌套多
- 占内存,可能导致内存泄漏(闭包)
- 效率差(递归)
- 变量存取慢(
arguments
)