词法范围/闭包和全局函数递归

时间:2015-12-09 18:57:15

标签: javascript closures lexical-scope

这既是词汇范围的一个例子,也是一个确认我自己理解的问题。首先,请考虑以下示例:

HTML:

<div id="testtxt"></div>

JS:

function fnTest(currentIdx, endIdx) {
    $('#testtxt').html($('#testtxt').html() + 'Function Called ' + currentIdx + '<br />');
    if (currentIdx < endIdx) {
        setTimeout(function(){ 
            fnTest(currentIdx + 1, endIdx); 
        }, 100);
    }
}

fnTest(1, 10);
fnTest(11, 20);

输出:

Function Called 1
Function Called 11
Function Called 2
Function Called 12
Function Called 3
Function Called 13
Function Called 4
Function Called 14
Function Called 5
Function Called 15
Function Called 6
Function Called 16
Function Called 7
Function Called 17
Function Called 8
Function Called 18
Function Called 9
Function Called 19
Function Called 10
Function Called 20

当我第一次运行这个例子时,我担心fnTest会有一个全局闭包,因此两个fnTest调用都会设置和访问currentIdx和endIdx。但事实并非如此。

如果以下是解释它的好方法,请告诉我:

每次调用fnTest都会创建一个唯一的对象,其中变量currentIdx和endIdx存储在该调用的生命周期内以及该调用中的所有子例程(这称为闭包)。 setTimeout调用从匿名函数创建一个新对象,该对象可以访问fnTest闭包,因此可以引用currentIdx和endIdx,此对象/函数将在100ms延迟后执行。执行时,匿名函数本身将通过调用fnTest创建一个新的fnTest闭包。此时,可以处理匿名函数引用的原始fnTest闭包。

请在必要时更正我的技术术语。

1 个答案:

答案 0 :(得分:2)

基本上是对的,有几点:

  

每次调用fnTest都会创建一个唯一的对象,其中变量currentIdx和endIdx存储在该调用的生命周期中......

对于该对象的生命周期,Felix称之为 environment 。那个生命就像所有其他物体的生命周期:只要有东西仍然有它的参考。特别是,在fnTest返回后,它会继续(在这种情况下)。

唯一可以引用这些环境对象的东西就是在它们中创建的函数,它们被称为闭包(它们&#34;关闭&#34;环境)。

  

...以及该调用中的所有子例程(这称为闭包)

这些函数称为闭包,而不是环境。

  

setTimeout调用从匿名函数

创建一个新对象

不,您的代码正在创建一个匿名函数,并将对该函数的引用传递给setTimeout

  

...可以访问fnTest闭包,因此可以引用currentIdx和endIdx

它可以访问创建它的环境

  

此对象/函数将在100ms延迟后执行。在执行时,匿名函数本身将通过调用fnTest创建一个新的fnTest闭包。

通过调用fnTest创建一个新环境,是的。

  

此时,匿名函数引用的原始fnTest闭包可能会被处理掉。

由于计时器机制已经释放了它对匿名函数的引用,因此不再引用匿名函数,它可以被垃圾收集。由于它是从最初调用fnTest引用环境的唯一内容,因此该环境也可以被垃圾收集。

我们在上面的细节中做了一个小小的小小的位,但重要的概念是正确的。