编者按:
在Javascript中所有的功能都关闭在这个解释后但是,我们只对确定这些功能的子集感兴趣,这从理论上讲是很[有趣的。此后,除非另有说明,否则对闭包一词的任何引用都将指代此功能子集。
闭包的简单说明:
- 发挥作用。我们称它为F。
- 列出F的所有变量。
- 变量可以有两种类型:
- 局部变量(绑定变量)
- 非局部变量(自由变量)
- 如果F没有自由变量,则它不能是闭包。
- 如果F具有任何自由变量(在F 的 父范围中定义),则:
- 必须有其中的F只有一个父范围 一个 自由变量绑定。
- 如果从 该* 父作用域之外 引用 F ,则它将成为 该 自由变量的闭包。 ***
- 该 自由变量称为闭包F的升值。
现在,让我们用它来找出谁使用闭包,谁不使用闭包(为便于说明,我将函数命名为):
情况1:您朋友的程序
for (var i = 0; i < 10; i++) { (function f() { var i2 = i; setTimeout(function g() { console.log(i2); }, 1000); })();}在以上程序中,有两个功能:
f和
g。让我们看看它们是否为闭包:
对于
f:
- 列出变量:
i2
是 局部 变量。i
是一个 自由 变量。setTimeout
是一个 自由 变量。g
是 局部 变量。console
是一个 自由 变量。
- 查找每个自由变量绑定到的父范围:
i
被 绑定 到了全球范围。setTimeout
被 绑定 到了全球范围。console
被 绑定 到了全球范围。
- 该功能在哪个范围内 引用 ?在 全球范围内 。
- 因此
i
没有 关闭了 通过f
。 - 因此
setTimeout
没有 关闭了 通过f
。 - 因此
console
没有 关闭了 通过f
。
- 因此
因此,该功能
f不是闭包。
对于
g:
- 列出变量:
console
是一个 自由 变量。i2
是一个 自由 变量。
- 查找每个自由变量绑定到的父范围:
console
被 绑定 到了全球范围。i2
被 绑定 到的范围f
。
- 该功能在哪个范围内 引用 ?的 范围
setTimeout
。- 因此
console
没有 关闭了 通过g
。 - 因此
i2
被 封闭在 通过g
。
- 因此
因此,该功能
g是用于自由变量的封闭
i2(这是用于的upvalue
g) 当 它的 引用 从内
setTimeout。
对您不利: 您的朋友正在使用闭包。内部函数是一个闭包。
情况2:您的程序
for (var i = 0; i < 10; i++) { setTimeout((function f(i2) { return function g() { console.log(i2); }; })(i), 1000);}在以上程序中,有两个功能:
f和
g。让我们看看它们是否为闭包:
对于
f:
- 列出变量:
i2
是 局部 变量。g
是 局部 变量。console
是一个 自由 变量。
- 查找每个自由变量绑定到的父范围:
console
被 绑定 到了全球范围。
- 该功能在哪个范围内 引用 ?在 全球范围内 。
- 因此
console
没有 关闭了 通过f
。
- 因此
因此,该功能
f不是闭包。
对于
g:
- 列出变量:
console
是一个 自由 变量。i2
是一个 自由 变量。
- 查找每个自由变量绑定到的父范围:
console
被 绑定 到了全球范围。i2
被 绑定 到的范围f
。
- 该功能在哪个范围内 引用 ?的 范围
setTimeout
。- 因此
console
没有 关闭了 通过g
。 - 因此
i2
被 封闭在 通过g
。
- 因此
因此,该功能
g是用于自由变量的封闭
i2(这是用于的upvalue
g) 当 它的 引用 从内
setTimeout。
对您有好处: 您正在使用闭包。内部函数是一个闭包。
因此,您和您的朋友都在使用闭包。别吵了 我希望我清除了闭包的概念以及如何为你们两个人识别它们。
编辑: 关于为什么所有函数都关闭的简单说明(点数@Peter):
首先让我们考虑以下程序(它是control):
lexicalScope();function lexicalScope() { var message = "This is the control. You should be able to see this message being alerted."; regularFunction(); function regularFunction() { alert(eval("message")); }}- 我们知道,无论
lexicalScope
和regularFunction
不封闭 ,从上面的定义 。 - 当我们执行程序时, 我们希望
message
收到警告, 因为regularFunction
它不是闭包的(即它可以访问其父作用域中的 所有 变量-包括message
)。 - 当我们执行程序时, 我们观察 到
message
确实确实有警报。
接下来让我们考虑以下程序(这是替代程序):
var closureFunction = lexicalScope();closureFunction();function lexicalScope() { var message = "This is the alternative. If you see this message being alerted then in means that every function in Javascript is a closure."; return function closureFunction() { alert(eval("message")); };}- 我们知道,这只是 上述定义*
closureFunction
的闭包。 * - 当我们执行程序时, 我们希望*
message
不会 因为closureFunction
闭包而收到警告(即,在 创建函数时, 它只能访问其所有 非局部变量 (请参见此答案)-不包括)。 *message
- 当我们执行程序时, 我们观察 到
message
实际上正在被警告。
我们从中得出什么呢?
- Javascript解释器对待闭包的方式与对待其他函数的方式没有区别。
- 每个功能都带有其作用域链。闭包没有 单独的 引用环境。
- 闭包就像其他函数一样。当在它们所属的范围 之外* 的范围中 引用 它们时,我们只称它们为闭包, 因为 这是一个有趣的情况。 ***



