返回字符串而不是函数的Javascript闭包

返回字符串而不是函数的Javascript闭包,javascript,closures,Javascript,Closures,我正在尝试编写一个简单的compose函数,它包含一系列函数,并按如下方式进行组合: compose(func1, func2, func3)(n) === func1(func2(func3(n))) 我通过递归rest参数来实现 var compose = function(...args) { return (n) => { if (args.length) { return args[0](compose(args.slice(1)

我正在尝试编写一个简单的
compose
函数,它包含一系列函数,并按如下方式进行组合:

compose(func1, func2, func3)(n) === func1(func2(func3(n)))
我通过递归rest参数来实现

var compose = function(...args) {
    return (n) => {
        if (args.length) {
            return args[0](compose(args.slice(1)));
        } else {
            return n;
        }
    };
};
然后我尝试编写一个由一系列其他函数组成的新函数

var plusOneAndTwo = compose((n) => n + 1, (n) => n + 2);
plusOneAndTwo(1);
我没有返回4,而是将
compose
中的内部匿名函数体作为字符串返回

"(n) => {
        if (args.length) {
            return args[0](compose(args.slice(1)));
        } else {
            return n;
        }
    }1"
注意字符串末尾的
“1”
!我不知道为什么会发生这种情况,尤其是我对1是如何附加到它的末尾感到困惑


任何澄清都将不胜感激,谢谢

您只需调用组合函数:

 return args[0](compose(...args.slice(1))(n));
或者如果没有递归,它将是:

 const compose = (...fns) => start => fns.reduceRight((acc, fn) => fn(acc), start);

您只需调用组合函数:

 return args[0](compose(...args.slice(1))(n));
或者如果没有递归,它将是:

 const compose = (...fns) => start => fns.reduceRight((acc, fn) => fn(acc), start);

问题发生在对compose的递归调用中。 特别是,您没有将参数
n
传递给它(正如上面其他人所建议的那样)。此外,您需要在调用中展开rest参数

您应该使用以下内容:

return args[0](compose(...args.slice(1))(n))
在您的情况下,您只是返回:

return args[0](compose(args.slice(1)));
在您的示例中,您调用
compose((n)=>n+1,(n)=>n+2)。然后,Compose返回一个以
n
为参数的函数。在此函数中,args.length变为1(即true is),args[0]变为
(n)=>n+1
,args.slice(1)变为
[(n)=>n+2]

接下来,使用参数
n=1
调用此返回函数。由于args.length为1,if()语句将进入if()情况。在这种情况下,它将使用参数
compose(args.slice(1))
调用args[0]

在这个递归调用中,compose(args.slice(1))被计算为一个函数,将n作为一个参数和相同的函数体。 然后将此函数作为参数
n
提供给args[0](在外部调用中)。回想一下,本场景中的args[0]是函数
(n)=>n+1

因此,整个调用相当于:

// returned from the recursive call to compose(args.slice(1))
var n = (n) => {
        if (args.length) {
            return args[0](compose(args.slice(1)));
        } else {
            return n;
        }
}
// applied to arg[0] == (n) => n + 1
return n + 1
这意味着代码将尝试添加数字为1的函数。
在JavaScript中,添加一个函数和一个数字会导致将两个对象强制转换为字符串。将数字转换成字符串是很简单的,将函数转换成字符串将返回函数源代码。然后添加这些字符串以给出您看到的返回值:函数体是一个字符串,末尾是1

问题发生在对compose的递归调用中。 特别是,您没有将参数
n
传递给它(正如上面其他人所建议的那样)。此外,您需要在调用中展开rest参数

您应该使用以下内容:

return args[0](compose(...args.slice(1))(n))
在您的情况下,您只是返回:

return args[0](compose(args.slice(1)));
在您的示例中,您调用
compose((n)=>n+1,(n)=>n+2)。然后,Compose返回一个以
n
为参数的函数。在此函数中,args.length变为1(即true is),args[0]变为
(n)=>n+1
,args.slice(1)变为
[(n)=>n+2]

接下来,使用参数
n=1
调用此返回函数。由于args.length为1,if()语句将进入if()情况。在这种情况下,它将使用参数
compose(args.slice(1))
调用args[0]

在这个递归调用中,compose(args.slice(1))被计算为一个函数,将n作为一个参数和相同的函数体。 然后将此函数作为参数
n
提供给args[0](在外部调用中)。回想一下,本场景中的args[0]是函数
(n)=>n+1

因此,整个调用相当于:

// returned from the recursive call to compose(args.slice(1))
var n = (n) => {
        if (args.length) {
            return args[0](compose(args.slice(1)));
        } else {
            return n;
        }
}
// applied to arg[0] == (n) => n + 1
return n + 1
这意味着代码将尝试添加数字为1的函数。
在JavaScript中,添加一个函数和一个数字会导致将两个对象强制转换为字符串。将数字转换成字符串是很简单的,将函数转换成字符串将返回函数源代码。然后添加这些字符串以给出您看到的返回值:函数体是一个字符串,末尾是1

您可以采用另一种方法,返回一个新函数或返回最后一个带参数调用的函数

const
组合=(…fns)=>fns.length
? v=>compose(…fns.slice(0,-1))(fns.pop()(v))
:v=>v,
fn1=n=>n*5,
fn2=n=>n+2,
fn3=n=>n*7;
console.log(fn1(fn2(fn3(1)));

日志(组成(fn1,fn2,fn3)(1))您可以采用不同的方法,返回新函数或返回最后一个用于调用参数的函数

const
组合=(…fns)=>fns.length
? v=>compose(…fns.slice(0,-1))(fns.pop()(v))
:v=>v,
fn1=n=>n*5,
fn2=n=>n+2,
fn3=n=>n*7;
console.log(fn1(fn2(fn3(1)));

日志(组成(fn1,fn2,fn3)(1))
compose
返回函数,是。您正在将函数
compose
的返回值传递给
args[0]()
。我认为递归地使用
compose
不是一个好主意。我只想
。减少
参数
。@deceze我希望compose返回一个函数。但是,当我调用由compose返回的函数时,它的主体是一个字符串。这就是我所困惑的。编辑:啊,好吧,我明白你的意思了。谢谢
compose(args.slice(1))
您实际上并不像在初始调用中那样在此处调用compose返回的函数,而是将该函数用作args[0]的参数,而不是调用它的结果。不,关键在于
args[0](compose(…)
。这会将一个函数传递到
(n)=>n+1
,它将
1
连接到函数体。@deceze非常感谢,这很有意义,神秘解释
compose
返回函数,是。您正在将函数
compose
的返回值传递给
args[0]()