写作不易,Star是最大鼓励,感觉写的不错的可以给个Star⭐,请多多指教。Github地址。
题目
如何实现 multi(2)(3)(4)=24?
首先来分析下这道题,实现一个multi函数并依次传入参数执行,得到最终的结果。通过题目很容易得到的结论是,把传入的参数相乘就能够得到需要的结果,也就是2*3*4 = 24
。
function multi(a) {
return function(b) {
return function(c) {
return a * b * c;
}
}
}
1
2
3
4
5
6
7
2
3
4
5
6
7
利用闭包的原则,multi函数执行的时候,返回multi函数中的内部函数,再次执行的时候其实执行的是这个内部函数,这个内部函数中接着又嵌套了一个内部函数,用于计算最终结果并返回。
单纯从题面来说,似乎是已经实现了想要的结果,但仔细一想就会发现存在问题。 上面的实现方案存在的缺陷:
- 代码不够优雅,实现步骤需要一层一层的嵌套函数。
- 可扩展性差,假如是要实现
multi(2)(3)(4)...(n)
这样的功能,那就得嵌套n
层函数。
那么有没有更好的解决方案,答案是:使用函数式编程中的函数柯里化实现。
函数柯里化
函数柯里化是指:将能够接收多个参数的函数转化为接收单一参数的函数,并且返回接收余下参数且返回结果的新函数的技术。
函数柯里化的主要作用和特点是:参数复用、提前返回和延迟执行。
function curry(fn) {
console.log(arguments); // { '0': [Function: add], '1': 5 }
var args = Array.prototype.slice.call(arguments, 1);
return function() {
console.log(arguments); // { '0': 3 }
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return fn.apply(null, finalArgs);
}
}
function add(num1, num2) {
return num1 + num2;
}
var curriedAdd = curry(add, 5);
console.log(curriedAdd(3)); // 8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function curry_fn(fn, curArgs) {
return function() {
let args = Array.prototype.slice.call(arguments); // 将类数组变为数组
if (curArgs !== undefined) {
args = args.concat(curArgs);
}
// console.log(fn.length); // 3 fn函数形参的个数
if (args.length < fn.length) {
return curry_fn(fn, args);
}
return fn.apply(null, args);
};
}
function sum(a, b, c) {
return a + b + c;
}
const fn = curry_fn(sum);
console.log(fn(1, 2, 3)); // 6
console.log(fn(1)(2)(3)); // 6
console.log(fn(1, 2)(3)); // 6
console.log(fn(1)(2, 3)); // 6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
实现
function curry_fn(fn) {
const outerArgs = [...arguments].slice(1);
return function () {
const innerArgs = [...arguments];
let allArgs = [];
if (outerArgs.length) {
allArgs = [...outerArgs, ...innerArgs];
}
else {
allArgs = [...innerArgs];
}
// fn.length是sum函数的形参个数
if (allArgs.length < fn.length) {
// 递归
return curry_fn(fn, ...allArgs);
}
// 递归出口
return fn.apply(null, allArgs);
}
}
function sum(a, b, c) {
return a + b + c;
}
const fn = curry_fn(sum);
console.log(fn(1, 2, 4)); // 7
console.log(fn(1)(2)(4)); // 7
console.log(fn(1, 2)(4)); // 7
console.log(fn(1)(2, 4)); // 7
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
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
实现sum(1,2,3)==sum(1)(2)(3)
function sum(...args){
function currySum(...rest){
args.push(...rest)
return currySum
}
currySum.toString= function(){
return args.reduce((result,cur)=>{
return result + cur
})
}
currySum.toNumber= function(){
return args.reduce((result,cur)=>{
return result + cur
})
}
return currySum
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17