Skip to content

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

其实这可以理解为

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

那么最初的做法可以是:

js
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 一个变量值,而不是函数对象。

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

js
function add(n1) {
  var sum = 0
  sum += n1
  return function(n2) {
    sum += n2
    return function(n3) {
      sum += n3
      return function(nn) {/* xxx */}
    }
  }
}

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

js
function add(n1) {
  var sum = 0
  sum += n1
  return function add2(n2) {
    sum += n2
    return add2
  }
}

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

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

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

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

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

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

js
function add(n1) {
  var sum = 0
  if (arguments.length === 0) return sum
  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类型
js
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
}

另一种实现方法

js
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
})()

共 20 个模块,1301 篇 Markdown 文档。