该函数如何不使用额外的参数

时间:2014-01-30 20:28:27

标签: javascript

这个JavaScript来自他JavaScript Ninja书中的Resig代码:

function yell(n){ 
  return n > 0 ? yell(n-1) + "a" : "hiy"; 
} 
assert( yell(4) == "hiyaaaa", "Calling the function by itself comes naturally." );

所以这是一些简单的递归。我理解递归。这可能是一个愚蠢的问题。但是,我不明白为什么这个代码行如此之少。 "aaaa"附加到"hiy"的位置在哪里?如果我在Prolog中这样做,我想我会在yell添加一个额外的参数来跟踪正在构建的字符串。

3 个答案:

答案 0 :(得分:2)

让我们将呼叫分解为yell(3)

yell(3) - n > 0 ? yell(2) + "a" : "hiy";
yell(2) - n > 0 ? yell(1) + "a" : "hiy";
yell(1) - n > 0 ? yell(0) + "a" : "hiy";
yell(0) - n > 0 ? yell(-1) + "a" : "hiy";

我们可以评估条件表达式:

yell(3) - yell(2) + "a";
yell(2) - yell(1) + "a";
yell(1) - yell(0) + "a";
yell(0) - "hiy";

然后继续替换/简化:

yell(3) - (yell(1) + "a") + "a";          // since yell(2) = yell(1) + "a"

yell(3) - ((yell(0) + "a") + "a") + "a";  // since yell(1) = yell(0) + "a"

yell(3) - (("hiy" + "a") + "a") + "a";    // since yell(0) = "hiy"

你有它。

这有效的一个重要原因是?:运算符使用短路评估,并且仅根据条件的结果评估相关的部分。如果没有,则此函数将导致无限递归。

答案 1 :(得分:2)

此函数通过在每一步将"a"附加到 next 调用的返回值来构建字符串。可视化调用堆栈可能有所帮助:

yell(4) = yell(3) + "a"
yell(3) = yell(2) + "a"
yell(2) = yell(1) + "a"
yell(1) = yell(0) + "a"
yell(0) = "hiy"

我们现在拥有了解其工作原理所需的所有信息。我们只需要“展开”堆栈并将其重新插入:

yell(1) = "hiy" + "a"
yell(2) = "hiy" + "a" + "a"
yell(3) = "hiy" + "a" + "a" + "a"
yell(4) = "hiy" + "a" + "a" + "a" + "a"

所以最后的结果是:

"hiyaaaa"

您不需要额外参数的原因是递归的任何阶段都不需要访问之前的步骤中的值。相反,每个值都会返回其值与进展中 next 值的组合。

答案 2 :(得分:0)

您可以将三元运算符?:重写为

function yell(n) {
    if (n > 0)
        return yell(n - 1) + "a";
    else
        return "hiy";
}

该函数以参数n - 1递归调用自身,直到参数n变为0,并返回hiy。然后递归递归,每个递归级别附加一个a