这既是词汇范围的一个例子,也是一个确认我自己理解的问题。首先,请考虑以下示例:
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闭包。
请在必要时更正我的技术术语。
答案 0 :(得分:2)
基本上是对的,有几点:
每次调用fnTest都会创建一个唯一的对象,其中变量currentIdx和endIdx存储在该调用的生命周期中......
对于该对象的生命周期,Felix称之为 environment 。那个生命就像所有其他物体的生命周期:只要有东西仍然有它的参考。特别是,在fnTest
返回后,它会继续(在这种情况下)。
唯一可以引用这些环境对象的东西就是在它们中创建的函数,它们被称为闭包(它们&#34;关闭&#34;环境)。
...以及该调用中的所有子例程(这称为闭包)
这些函数称为闭包,而不是环境。
setTimeout调用从匿名函数
创建一个新对象
不,您的代码正在创建一个匿名函数,并将对该函数的引用传递给setTimeout
。
...可以访问fnTest闭包,因此可以引用currentIdx和endIdx
它可以访问创建它的环境
此对象/函数将在100ms延迟后执行。在执行时,匿名函数本身将通过调用fnTest创建一个新的fnTest闭包。
通过调用fnTest
创建一个新环境,是的。
此时,匿名函数引用的原始fnTest闭包可能会被处理掉。
由于计时器机制已经释放了它对匿名函数的引用,因此不再引用匿名函数,它可以被垃圾收集。由于它是从最初调用fnTest
引用环境的唯一内容,因此该环境也可以被垃圾收集。
我们在上面的细节中做了一个小小的小小的位,但重要的概念是正确的。