Javascript 什么是;返回a";在这个递归组合函数中是什么?

Javascript 什么是;返回a";在这个递归组合函数中是什么?,javascript,recursion,permutation,Javascript,Recursion,Permutation,我在Chrome调试器中反复检查了这个函数,但仍然不明白返回a的作用。谢谢你帮助我 以下是一些澄清: 我理解第一轮。使用以下参数调用匿名函数: active=“”,rest=“abc”,a=[] 然后,当它填充a数组时,它调用自己,直到rest为空: active=“abc”,rest=“”,a=[“abc”] 此时,我们将返回一个,调试器将跳转到else语句中的第二个fn调用,而不是第一个if语句。参数已经如下所示: active=“ab”,rest=“c”,a=[“abc”] 这部分我一点也

我在Chrome调试器中反复检查了这个函数,但仍然不明白
返回a
的作用。谢谢你帮助我

以下是一些澄清: 我理解第一轮。使用以下参数调用匿名函数:

active=“”,rest=“abc”,a=[]

然后,当它填充
a
数组时,它调用自己,直到
rest
为空:

active=“abc”,rest=“”,a=[“abc”]

此时,我们将返回一个,调试器将跳转到else语句中的第二个fn调用,而不是第一个if语句。参数已经如下所示:

active=“ab”,rest=“c”,a=[“abc”]

这部分我一点也不懂。我知道递归只有在
active
rest
为空时才会结束,但在
返回a
之后,if语句甚至没有在调试器中得到检查,它只会突出显示提到的第二个函数调用,此时“c”已经分配给
rest
。我猜这个函数不产生副本的原因也在这里,但如果不是,那可能是另一个问题。无论如何,再次感谢你的帮助

combinations("abc");

function combinations(str) {
    var fn = function(active, rest, a) {
        if (!active && !rest)
            return;
        if (!rest) {
            a.push(active);
        } else {
            fn(active + rest[0], rest.slice(1), a);
            fn(active, rest.slice(1), a);
        }
        return a;
    }
    return fn("", str, []);
}

在这种情况下,递归构造编写得很奇怪,“returna”只是将最初提供的相同对象的变异数组偷偷带回到helper函数,以便在内部递归函数调用中使用直接返回。(在大多数上下文中,递归函数通常使用返回值。)

下面是一个更清晰的使用helper函数的重写。我还删除了所有显式返回语句,因为它们没有在这里增加值

function combinations(str) {
    var fn = function(active, rest, a) {
        if (!active && !rest) {
            // base case #1 - implicit return, no recursive call
        } else if (!rest) {
            // base case #2 - implicit return, no recursive call
            a.push(active);
        } else {
            // recursive case, where function is called again
            // (the object "a" is modified in recursion;
            //  result of recursion not directly used)
            fn(active + rest[0], rest.slice(1), a);
            fn(active, rest.slice(1), a);
        }
    }

    var o = [];     // only one output object created..
    fn("", str, o); // ..mutated..
    return o;       // ..and returned to caller.
}
然后应该很容易观察到,不需要将“a”传递给递归函数(即,它可以访问封闭范围中的“o”),因为在创建初始结果数组之后,没有为“a”分配新对象


重新写入将(更正确地)为空输入字符串返回一个空数组。在这种情况下,递归构造写得很奇怪,“返回a”只是为了偷偷输出变异数组,即最初提供的相同对象,返回helper函数,以便在内部递归函数调用中使用直接返回。(在大多数上下文中,递归函数通常使用返回值。)

下面是一个更清晰的使用helper函数的重写。我还删除了所有显式返回语句,因为它们没有在这里增加值

function combinations(str) {
    var fn = function(active, rest, a) {
        if (!active && !rest) {
            // base case #1 - implicit return, no recursive call
        } else if (!rest) {
            // base case #2 - implicit return, no recursive call
            a.push(active);
        } else {
            // recursive case, where function is called again
            // (the object "a" is modified in recursion;
            //  result of recursion not directly used)
            fn(active + rest[0], rest.slice(1), a);
            fn(active, rest.slice(1), a);
        }
    }

    var o = [];     // only one output object created..
    fn("", str, o); // ..mutated..
    return o;       // ..and returned to caller.
}
然后应该很容易观察到,不需要将“a”传递给递归函数(即,它可以访问封闭范围中的“o”),因为在创建初始结果数组之后,没有为“a”分配新对象


重写将(更正确地)为空输入字符串返回一个空数组,这有一个微妙的区别。

虽然我知道这个问题主要是关于特定递归实现的工作原理(对此已经有一个很好的答案!),但我认为值得指出的是,它是一个奇怪的实现,像这样的东西可能更干净:

const组合=(str,active=“”)=>
str.length==0
? 活动。长度==0
? []
:[现行]
: [
…组合(str.slice(1),active+str[0]),
…组合(str.slice(1),活动)
]

log(combinations('abc'))
虽然我知道这个问题主要是关于特定递归实现的工作原理(对此已经有了一个很好的答案!),但我认为值得指出的是,它是一个奇怪的实现,类似这样的实现可能更干净:

const组合=(str,active=“”)=>
str.length==0
? 活动。长度==0
? []
:[现行]
: [
…组合(str.slice(1),active+str[0]),
…组合(str.slice(1),活动)
]

log(combinations('abc'))
它从递归返回,这意味着在
返回之后,它将到达调用它的行。然后是第二行,进行第二次调用。函数的布局很奇怪。。也就是说,返回应该始终为“return;”(或者更好,两个返回都被消除!),并且helper函数应该返回经过修改的对象本身。那么,结尾的“return a;”显然是多余的。如上所述,“return a;”仅用于输出变异对象(假设终端大小写不是立即为真的),它本身与递归无关。@user2864740谢谢你的回答,我现在明白了!但最主要的是(因为我不小心删除了我以前的注释),第一个调用的参数被传递到第二个调用。@Premierplan如果它们被显式指定,则是:)这是由
fn(…,…,a)
eg.完成的,它与返回无关。它是从递归返回的,这意味着在
返回之后
将到达调用它的行。然后是第二行,进行第二次调用。函数的布局很奇怪。。也就是说,返回应该始终为“return;”(或者更好,两个返回都被消除!),并且helper函数应该返回经过修改的对象本身。那么,结尾的“return a;”显然是多余的。如上所述,“return a;”仅用于输出变异对象(假设终端大小写不是立即为真的),它本身与递归无关。@user2864740谢谢你的回答,我现在明白了!但最主要的是(因为我不小心删除了之前的注释),第一个调用的参数被传递到第二个调用。@Premierplan如果它们被显式指定,则为yes:)这是通过