4

我一直在更具体地阅读编程的闭包概念,尤其是与 Javascript 相关的内容。不过,我还没有完全理解它与我多年来编写的 Javascript 代码有何不同。我也理解递归的概念,但我想知道,闭包和递归有何相似之处?我是否正确理解递归本身就是一种闭包?

关闭:

function init() {
    var name = "Stack Overflow";
    function displayName() {
        alert(name);
    }
    displayName();
}
init();

递归:

function factorial(num) {
    if(num < 0)
        return -1;

    else if(num == 0)
        return 1;

    else
        return (num * factorial(num - 1));
}

alert(factorial(8));

我想我开始明白闭包只不过是在函数中拥有一个函数,内部函数可以通过范围访问外部函数。会不会有递归闭包?我的意思是,虽然我的递归示例也不完全是闭包的示例,但它至少会发生吗?我试图了解递归和闭包是如何相似、不同的,或者它们是否具有可比性。有什么例子可以描述这一点吗?

4

2 回答 2

9

闭包只是一个“关闭”环境(它的主体)的函数或过程。在您的代码中initdisplayName、 和factorial都是闭包。当你想创建一个闭包时,你可以使用 JavaScriptfunction关键字(或者现在我们在 ES6 中有箭头函数)。=>

递归是过程重复自身的效果


我一直在读一本新书,它谈到了一些相关的话题。我想我只是在这里分享一些笔记,以防你感兴趣。

这是一个用于计算阶乘的递归函数。它的作用与您的相同,但方式却截然不同。让我们来看看!

function factorial(x) {
  if (x < 0) throw Error("Cannot calculate factorial of a negative number");
  function iter(i, fact) {
    return i === 0 ? fact : iter(i-1, i*fact);
  }
  return iter(x, 1);
}

factorial(6); // 720

将其与您在上面定义的^.^进行比较。请注意,即使它是递归的,它也不会factorial再次调用自身 ( )。这使用消耗线性空间和时间的线性迭代过程。函数的评估看起来像这样

factorial(6);
  iter(6, 1);
  iter(5, 6*1); 
  iter(4, 5*6);
  iter(3, 4*30);
  iter(2, 3*120);
  iter(1, 2*360);
  iter(0, 1*720);
// => 720

将其与您的功能过程进行比较。这是你的样子

factorial(6);
(6 * factorial(5));
(6 * (5 * factorial(4)));
(6 * (5 * (4 * factorial(3))));
(6 * (5 * (4 * (3 * factorial(2)))));
(6 * (5 * (4 * (3 * (2 * factorial(1))))));
(6 * (5 * (4 * (3 * (2 * 1)))));
// => 720

请注意,随着n增加,n!会添加另一个堆栈调用。这是一个线性递归过程。对于较大的 值n,此方法使用显着更多的空间来计算相同的结果。

于 2015-04-21T05:44:23.400 回答
2

我在这里之前尝试过写关于闭包的文章(虽然没有提到递归):

http://hangar.runway7.net/javascript/guide

但是关于递归,我想说当递归发生时,闭包可以发挥作用,但它们不一定相关。我实际上建议您根本不要在递归中使用闭包,因为这可能会导致意外错误。递归通常依赖于每个函数调用的执行,只知道显式传递给它的参数,而闭包违反了这一原则。

实际上,闭包是在定义函数时在函数之间共享信息的一种方式,尤其是当您知道它们将在未知上下文中执行时。

另一方面,递归是函数的执行过程,该函数的结构方式是通过重复调用自身来完成其工作。

通过谷歌搜索可以更好地学习这两个概念,但只需知道它们通常不相关。

于 2013-06-18T17:04:35.430 回答