闭包 JS基础 编程题

瓶子君
  • 557

var foo = function(...args) { // 要求实现函数体}
var f1 = foo(1,2,3); f1.getValue(); // 6 输出是参数的和
var f2 = foo(1)(2,3); f2.getValue(); // 6
var f3 = foo(1)(2)(3)(4); f3.getValue(); // 10

回复
阅读 256
2 个回答
(function() {

    let foo = function(...args) {
        let argsArr = args

        function _add() {
            argsArr.push(...arguments)
            return _add;

        }
        _add.getValue = function() {
            let sum = argsArr.reduce(function(a, b) {
                return a + b
            })
            console.log(sum)

            return sum
        }
        return _add;
    }
    let f1 = foo(1, 2, 3)
    f1.getValue()
    let f2 = foo(1)(2, 3)
    f2.getValue()

    let f3 = foo(1)(2)(3)(4)
    f3.getValue()
}
)()
  • 根据结果是通过 f1.getValue() 来取值,说明 foo() 返回一个对象
  • 根据结果 foo(1)(...) 说明 foo() 返回一个函数,可以理解为参数只有 1 个时返回函数
  • 根据结果 foo(...)(4).getValue() 说明 foo() 在参数只有1 个的时候也可能返回对象

综上,foo() 返回一个带额外属性(.getValue)的函数。

  • 当它作为一个函数使用的时候,其行为和 foo() 是一致的,可以考虑递归调用 foo()
  • 当它作为对象的时候,需要通过 getValue() 返回计算结果,所以这个结果可以在 getValue() 中计算出来,也可以作为一个对象状态(属性)保存起来
  • 由于存在函数连调 foo()(),而且后面的调用会累加前面的结果,所以上面一条中提及的计算结果用状态保存比较好,即可以用于后面的计算,也可以通过 getValue() 返回出去

综上分析:

var foo = function (...args) {
    // 函数,是将当前状态值和参数累加
    const add = (...moreArgs) => foo(add.sum, ...moreArgs);
    
    // sum 状态是当前参数的和
    add.sum = args.reduce((s, n) => s + n, 0);
    
    add.getValue = () => add.sum;
    return add;
}

这个问题的关键点不在于闭包(当然会用到闭包),而是柯里化的过程分析。

不过如果你想深入了解闭包可以看看这篇:还搞不懂闭包算我输(JS 示例)

@circle 的答案比我的简单,更容易理解。他那个是闭包实现的答案,更符合题主要求!把那个答案改写一下,不保存参数列表,直接保存中间结果是这样:

var foo = function (...args) {
    let sum = 0;

    const add = (...more) => {
        sum = more.reduce((s, n) => s + n, sum);
        return add;
    };
    add.getValue = () => sum;

    add(...args);
    return add;
}
你知道吗?

宣传栏