词法 Scope/Closures 和全局函数递归
Lexical Scope/Closures and Global Function Recursion
这既是一个词法范围的例子,也是一个确认我自己理解的问题。首先,考虑以下示例:
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 会有一个全局闭包,因此 currentIdx 和 endIdx 会被 fnTest 的两个调用设置和访问。然而事实并非如此。
请让我知道以下是否是解释它的好方法:
每次调用 fnTest 都会创建一个唯一的对象,其中变量 currentIdx 和 endIdx 会在该调用和该调用中的所有子例程的生命周期内存储(这称为闭包)。 setTimeout 调用从匿名函数创建一个新对象,该对象可以访问 fnTest 闭包,因此可以引用 currentIdx 和 endIdx,此 object/function 将在 100 毫秒延迟后执行。在执行时,匿名函数本身将通过调用 fnTest 创建一个新的 fnTest 闭包。此时匿名函数引用的原始fnTest闭包可能会被处理掉。
请在必要时更正我的技术术语。
基本正确,几点:
Each call to fnTest creates a unique object in which the variables currentIdx and endIdx are stored for the lifetime of that call...
对于那个对象的生命周期,正如 Felix 所说,它被称为 环境。该生命周期就像所有其他对象的生命周期一样:只要某物仍然有对它的引用。特别是,它会在 fnTest
返回后继续(在本例中)。
唯一可以引用这些环境对象的是在其中创建的函数,称为闭包(它们 "close over" 环境)。
...and all sub-routines within that call (this is called a closure)
函数称为闭包,而不是环境。
The setTimeout call creates a new object from the anonymous function
不,您的代码正在创建一个匿名函数并将对该函数的引用传递给 setTimeout
。
...which has access to the fnTest closure and can therefore reference currentIdx and endIdx
它可以访问创建它的环境
this object/function will execute after a 100ms delay. Upon execution the anonymous function will itself create a new fnTest closure by calling fnTest.
它通过调用 fnTest
创建了一个新环境,是的。
At this point the original fnTest closure referenced by the anonymous function may be disposed of.
由于定时器机制已经释放了它对匿名函数的引用,所以没有任何东西再引用匿名函数,它可以被垃圾回收。因为它是从初始调用到 fnTest
引用环境的唯一事物,所以该环境也可以被垃圾收集。
我们对上面的细节做了一些 的修改,但重要的概念是正确的。
这既是一个词法范围的例子,也是一个确认我自己理解的问题。首先,考虑以下示例:
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 会有一个全局闭包,因此 currentIdx 和 endIdx 会被 fnTest 的两个调用设置和访问。然而事实并非如此。
请让我知道以下是否是解释它的好方法:
每次调用 fnTest 都会创建一个唯一的对象,其中变量 currentIdx 和 endIdx 会在该调用和该调用中的所有子例程的生命周期内存储(这称为闭包)。 setTimeout 调用从匿名函数创建一个新对象,该对象可以访问 fnTest 闭包,因此可以引用 currentIdx 和 endIdx,此 object/function 将在 100 毫秒延迟后执行。在执行时,匿名函数本身将通过调用 fnTest 创建一个新的 fnTest 闭包。此时匿名函数引用的原始fnTest闭包可能会被处理掉。
请在必要时更正我的技术术语。
基本正确,几点:
Each call to fnTest creates a unique object in which the variables currentIdx and endIdx are stored for the lifetime of that call...
对于那个对象的生命周期,正如 Felix 所说,它被称为 环境。该生命周期就像所有其他对象的生命周期一样:只要某物仍然有对它的引用。特别是,它会在 fnTest
返回后继续(在本例中)。
唯一可以引用这些环境对象的是在其中创建的函数,称为闭包(它们 "close over" 环境)。
...and all sub-routines within that call (this is called a closure)
函数称为闭包,而不是环境。
The setTimeout call creates a new object from the anonymous function
不,您的代码正在创建一个匿名函数并将对该函数的引用传递给 setTimeout
。
...which has access to the fnTest closure and can therefore reference currentIdx and endIdx
它可以访问创建它的环境
this object/function will execute after a 100ms delay. Upon execution the anonymous function will itself create a new fnTest closure by calling fnTest.
它通过调用 fnTest
创建了一个新环境,是的。
At this point the original fnTest closure referenced by the anonymous function may be disposed of.
由于定时器机制已经释放了它对匿名函数的引用,所以没有任何东西再引用匿名函数,它可以被垃圾回收。因为它是从初始调用到 fnTest
引用环境的唯一事物,所以该环境也可以被垃圾收集。
我们对上面的细节做了一些 的修改,但重要的概念是正确的。