函数柯里化 和函数反柯里化
函数柯里化
柯里化的定义:柯里化是将使用多个参数的一个函数,通过拆分参数的方式,转换成一系列使用一个参数的函数。
函数的柯里化,返回的是一个参数的函数。其实现方式是需要依赖参数以及递归,通过拆分参数的方式,来调用一个多参数的函数方法,增加可读性的目的。
js
function isType(value, type) {
return Object.prototype.toString.call(value) === `[object ${type}]`
}
console.log(isType([], 'Array'))
//true
//把上面的函数通过拆分参数的方式,将使用多个参数的一个函数转换成一系列使用一个参数的函数
function isType(type) {
return function (value) {
return Object.prototype.toString.call(value) === `[object ${type}]`
}
}
let isArry = isType('Array')
console.log(isArry([]))
//true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
柯里化的通用化实现:
通过一个柯里化函数实现通用的柯里化方法
js
//支持多参数传递
//es6实现
function isType(type){
return function(value){
return Object.prototype.toString.call(value) === `[object ${type}]`
}
}
let currying = (fn,arr=[]) =>{
let len = fn.length; //这里获取的是函数参数的个数
// console.log(len)
return function(...args){ //每次执行传入的参数
//高阶函数
let _arr = [...arr, ...args] //合并上次传入的参数到arr数组
if (_arr.length < len) {
return currying(fn, _arr) //递归不停的产生函数
} else {
return fn(..._arr)
}
}
}
let isArray = currying(isType)('Array');
let isString = currying(isType)('String');
//es5实现
// 支持多参数传递
function currying(fn, args) {
var args = args || [];//用来存储所有传入的参数
var _this = this;
var len = fn.length;
return function () {
var _args = Array.prototype.slice.call(arguments) //把arguments转换成数组 用来存放每次递归传过来的参数
_args = args.concat(args)
// 如果参数个数小于fn.length,则递归调用,继续收集参数
if (_args.length < len) {
return currying.call(_this, fn, _args)
} else {
// 参数收集完毕,则执行fn
return fn.apply(_this, _args)
}
}
}
//ts实现
const curring = (fn:Function) =>{//sum
const exec =(sumArgs:any[]=[])=>{
return sumArgs.length<fn.length? (...args:any[]) =>exec([...sumArgs,...args]): fn(...sumArgs)
}
return exec() //用于收集每次传入的参数,第一次默认是空的
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
反柯里化
- 柯里化:方法的范围变小了(isType => isString/isArray) 方法的范围变小了
- 反柯里化:范围变大了
js
// ---------分割线----------------------
/* let toString = Object.prototype.toString;
console.log(toString.call(123))
*/
// ---------分割线----------------------
Function.prototype.unCurrying = function () {
return (...args) => {
//将所有参数组成一个数组
/* this.call 这样调用call方法,可能并不是原型上的call方法,可能是用户自己定义的
防止用户自定义了call方法,这里调用原型上的call方法
借用原型上的call方法 apply:主要就是改变this,并且传入参数
第一个call是找到call函数,第二个apply是让call执行
让call方法上的this变成了toString(...args),让toString执行
*/
return Function.prototype.call.apply(this, args)
}
}
let toString = Object.prototype.toString.unCurrying()
//toString原来只是原型上的,现在变成全局的了,其他原型的方法都可以通过这样变为全局的方法
console.log(toString(123))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
函数柯里化经典面试题:
js
function add(a, b, c, d, e) {
return a + b + c + d + e
}
let sum = currying(add)
console.log(sum(1, 2)(3, 4)(5))
1
2
3
4
5
2
3
4
5