# ❓ 请实现一个 add 函数,满足以下功能。
add(1); // 1
add(1)(2); // 3
add(1)(2)(3); // 6
add(1)(2, 3); // 6
add(1, 2)(3); // 6
add(1, 2, 3); // 6
# Coding
// // 这种写法只能满足前三个例子
// function add(a) {
// // 这里其实用了闭包
// function sum(b) {
// a = a + b
// return sum
// }
// // console.log 回调用toString方法
// sum.toString = () => a
// return sum
// }
// 函数柯里化
function curry(func) {
return function curried(...args) {
if (args.length >= func.length) {
return func.apply(this, args)
} else {
return function pass(...args2) {
return curried.apply(this, args.concat(args2))
}
}
}
}
// 箭头函数
// const curry = (func) =>
// (curried = (...args) =>
// args.length >= func.length
// ? func(...args)
// : (...args2) => curried(...args, ...args2))
function _add(a, b, c) {
return a + b + c
}
let add = currying(_add)
console.log('add(1)', add(1))
console.log('add(1)(2)', add(1)(2))
console.log('add(1)(2)(3)', add(1)(2)(3))
console.log('add(1)(2, 3)', add(1)(2, 3))
console.log('add(1, 2)(3)', add(1, 2)(3))
console.log('add(1, 2, 3)', add(1, 2, 3))
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
51
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
51
# 解析
function curry(func) {
// func 要转换的函数
return function curried(...args) {
if (args.length >= func.length) {
// (1)
return func.apply(this, args)
} else {
return function pass(...args2) {
// (2)
return curried.apply(this, args.concat(args2))
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
当我们运行它时,这里有两个 if
执行分支:
现在调用:如果传入的
args
长度与原始函数所定义的(func.length
)相同或者更长,那么只需要将调用传递给它即可。获取一个偏函数:否则,
func
还没有被调用。取而代之的是,返回另一个包装器pass
,它将重新应用curried
,将之前传入的参数与新的参数一起传入。然后,在一个新的调用中,再次,我们将获得一个新的偏函数(如果参数不足的话),或者最终的结果。