一道柯理化面试题

今天在群里聊天,有人发了一道面试题:

1
2
3
4
// 实现一个这样的函数。输出结果如下:
add(1).value // 1
add(1)(2).value // 5
add(1)(2)(3).value // 14

我第一个想法是 curry。但是网上都是这样的

1
2
3
4
5
6
7
8
9
10
11
12
var add = function(a) {
var sum = a;
var addMore = function(b) {
sum += b;
return addMore;
};
addMore.toString = function() {
return sum;
};
return addMore;
};
add(1)(2)(3)(4);

这只是简单的累加。但是我在 nodejs 的环境里是没办法想这样调用得到结果的。需要手动去调用一次toString()

幸好这道面试题是用一个value返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* @description
* @author bubao
* @date 2021-04-01
* @param {number} value
* @returns {number}
*/
function add(a) {
sum.i = 1;
function sum(b) {
sum.value += b * (++sum.i);
return sum;
}
sum.value = a;
return sum;
}

console.log(add(1).value);
console.log(add(1)(2).value);
console.log(add(1)(2)(3).value);

等等,这道题好像还有个问题,如果是 $value^2$ 的和呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* @description
* @author bubao
* @date 2021-04-01
* @param {number} value
* @returns {number}
*/
function add(a) {
sum.value = a ** 2;
function sum(b) {
sum.value += b ** 2;
return sum;
}
return sum;
}
console.log(add(1).value);
console.log(add(1)(2).value);
console.log(add(1)(2)(3).value);

但是如果我使用下面的方法,就不能保证每次运行都是相同的值了

1
2
3
4
const h = add(2);
console.log(h(3).value);
//
console.log(h(3).value);

所以改成这样

1
2
3
4
5
6
7
8
9
10
11
12
13
function reducer(a, f) {
// 合并 & 复制属性
return Object.assign(b => reducer(f(a, b), f), { value: a });
}

const add = reducer(0, (a, b) => a + b ** 2);

console.log(add(2));
console.log(add(1)(2).value);
console.log(add(1)(2)(3).value);
// 纯函数测试
const h = add(2);
console.log(h(3).value);