用多个括号关闭Javascript

时间:2013-08-15 11:50:31

标签: javascript closures

当没有传递任何参数括号时,任何人都能解释这个函数如何发出警报。我无法清楚地理解它。

function sum(a) {

  var sum = a

  function f(b) {
    sum += b
    return f
  }

  f.toString = function() { return sum }

  return f
}

alert( sum(1)(2) )  // 3
alert( sum(5)(-1)(2) )  // 6
alert( sum(6)(-1)(-2)(-3) )  // 0
alert( sum(0)(1)(2)(3)(4)(5) )  // 15

5 个答案:

答案 0 :(得分:18)

第一次调用函数时,第一个值存储在sum中。之后将返回function f(b),将临时结果保留在sum。每次连续调用都会执行函数f - 执行sum += b并再次返回f。如果需要字符串上下文(例如在alertconsole.log中),则调用f.toString,返回结果(sum)。

function sum(a) {

  var sum = a

  function f(b) {
    sum += b
    return f  //<- from second call, f is returned each time
              //   so you can chain those calls indefinitely
              //   function sum basically got "overridden" by f
  }

  f.toString = function() { return sum }

  return f //<- after first call, f is returned
}

说明:

alert( sum(6)(-1)(-2)(-3) )  // 0
           /\ function sum called, f returned
              /\ the returned function f is called, f returns itself
                  /\ again
                     /\ and again
                         /\ at last, alert() requires string context,
                            so f.toString is getting invoked now instead of f

答案 1 :(得分:3)

要看的是这段代码

function f(b) {
    sum += b
    return f
  }

此函数返回对自身的引用,因此可以尽可能多地调用它。一个重要的事情是它有一个被调用的tostring函数,因为tostring是在函数sum()中定义的,它可以访问变量sum及其值当前值(由{{更改) 1}})

答案 2 :(得分:2)

alert需要一个字符串。如果它没有得到一个字符串,它将尝试将它接收的任何对象(以及一个函数是一种对象)转换为一个。如果对象具有toString方法,则将调用该方法以执行所述转换。

答案 3 :(得分:1)

sumf函数始终返回f函数,您可以无限次地调用它而不会获得除函数之外的其他结果。

该值仅由toString的覆盖f方法返回(实际上返回一个数字):

console.log( sum(1)(2) ) // Function(){}
console.log( sum(1)(2).toString() ) // 3

alert函数在将其参数转换为字符串时隐式调用toString方法。

答案 4 :(得分:0)

它在所有情况下都没有按预期工作......问题是.toString应该返回一个字符串,因此提供的实现中的字符串方法不起作用,例如: G。 sum(2)(3).split()会导致错误。

虽然我们可能会假设sum()结果总是预期是一个数字,但在某些情况下可能不是这样,并且可能很难调试,例如: G。当我在jsbin.com上测试最初用.toString编写的代码时,我注意到了这个问题(它在内部的console.log参数上执行split,覆盖它。)

相反,.toString应该看起来像return String(result);.toString(当没有.valueOf或现代Symbol.toPrimitive)处理原语转换时,好的事情就是如此,因此期望数字的代码也会起作用。这里可能出现的问题可能是&#34; double&#34;由此引起的转换。

如果您只针对现代浏览器,则更好的解决方案可能是使用.toString.valueOf对,或只使用一个Symbol.toPrimitive

使用Symbol.toPrimitive的示例:

function sum(a) {
  let result = a;

  function f(b) {
    result += b;

    return f;
  }

  f[Symbol.toPrimitive] = hint => hint === 'string' ? String(result) : result;

  return f;
}

使用.toString.valueOf对的示例。

function sum(a) {
  var result = a;

  function f(b) {
    result += b;

    return f;
  }

  // avoiding double conversion which will happen in case of .toString
  f.valueOf = function() { return result; };
  f.toString = function() { return String(result); };

  return f;
}