【解题】写一个累加函数

也是最近看到的面试题,看似简单,其实有很多东西可学习理解。正好写到博客里进行下总结

add(2)(3)(4) 希望输出9

其实这可以理解为

  • add(2) 返回函数A
  • A(3) 返回函数B
  • B(4) 返回函数C
  • C函数运行的最终结果为 9

那么最初的做法可以是:

1
2
3
4
5
6
7
8
9
10
11
12
13
function add(n1) {
var sum = 0
sum += n1

return function(n2) {
sum += n2
return function(n3) {
sum += n3
return sum
}
}
}
var result = add(2)(3)(4) // 9

考虑其他的扩展性,若要求调用4次或者2次等,则上面的函数就不能满足这样的需求了。

那为什么不满足呢? 其原因是我们最后返回的结果是 sum 一个变量值,而不是函数对象。

那么,按前面的写法,改一下,使之继续返回函数:

1
2
3
4
5
6
7
8
9
10
11
function add(n1) {
var sum = 0
sum += n1
return function(n2) {
sum += n2
return function(n3) {
sum += n3
return function(nn) {/* xxx */}
}
}
}

问题是要调用的次数是未知的。就此可以利用链式调用,让函数返回后返回自身

1
2
3
4
5
6
7
8
function add(n1) {
var sum = 0
sum += n1
return function add2(n2) {
sum += n2
return add2
}
}

上述函数执行返回的结果是函数对象的字符串表示,怎样让之变位输出结果呢?

  1. 在函数中添加判断,当没有输入参数时,直接返回调用的结果而不是返回函数
1
2
3
4
5
6
7
8
9
function add(n1) {
var sum = 0
sum += n1
return function add2(n2) {
if (arguments.length === 0) return sum
sum += n2
return add2
}
}

在调用时,需要多加一个()

1
var result = add(2)(3)(4)(5)() // 14
  1. 利用JS对象到原始值的转换规则

当一个对象转换成原始值时,先查看对象是否有valueOf方法,如果有并且返回值是一个原始值,那么直接返回这个值;否则没有valueOf或返回的不是原始值,那么调用toString方法,返回字符串表示

我们就位函数对象添加一个valueOf方法和toString方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function add(n1) {
var sum = 0
sum += n1
var add2 = function(n2) {
if (arguments.length === 0) return sum
sum += n2
return add2
}

add2.valueOf = () => sum
add2.toString = () => sum + ''

return add2
}
add(1)(2)(3)(4) // function 10 这是toString返回的所以是字符串
add(1)(2)(3)(4)() // 10 number类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function add(n1) {
let sum = 0
sum += n1
function add2(n2) {
if (arguments.length === 0) return sum
sum += n2
return add2
}

add2.valueOf = () => sum
add2.toString = () => sum + ''

return add2
}

这是我在segmentFault看到的另一种实现方法,就直接抄过来了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var add = (function() {
var args = []
function add2() {
if (arguments.length === 0) {
return calRet
} else {
Array.prototype.push.apply(args, Array.prototype.splice.call(arguments, 0))
return add
}
}

function calRet() {
var result = args.reduce((acc, val) => acc + val, 0)
args = []
return result
}

add2.valueOf = () => calRet()
add2.toString = () => calRet() + ''

return add2
})()
Author: Fridolph
Link: http://blog.fridolph.wang/2016/09/21/【解题】写一个累加函数/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.