JS闭包和执行上下文的创建
JS closures and creation of execution context
你能在下面澄清我的误解吗?
如果 JS 中函数的执行上下文是在调用/调用函数时创建的,而不是在声明函数时创建的,那么在下面的代码中,内部是闭包吗?如果是这样,为什么?inner 尚未被调用,并且由于执行上下文是在调用时创建的,因此 inner 无法存储对 i 的引用。
function foo(i) {
function inner() {
return i;
}
return inner;
}
var f = foo(3);
内部何时引用 foo 的执行上下文?何时调用或何时定义?在上面的代码中,我还没有调用内部。
另外,如果您解释JS在看到函数定义时的作用(与函数调用/调用相反(,我将不胜感激
谢谢
请参阅有关其工作原理的评论。
function foo(i) {
function inner() { // closure or a new scope is created
return i; // but parent scope's variable can be used in child scope
}
return inner; // returning reference to function
}
var f = foo(3); // f contains the function reference
f(); // 3, since i is in the parent scope, it is retained.
由于 i
是一个形式参数,因此可以在整个函数中访问它,因为它位于最顶层的范围,没有任何闭包问题。
JavaScript 中的范围是以函数为中心的。因此,每当执行函数时,它都会创建一个闭包或作用域。
在我看来,在相互矛盾的答案中可能存在术语问题。 有一种设计概念称为闭包,可以说它是允许闭包的代码设计。 这显然会在守则的声明中发生。 这是一个设计概念,但由于尚未执行任何代码,因此没有包含变量值、对函数的引用等的实际对象......
还有一个实际的函数对象,它持续到执行其父函数的时间之后,这使得闭包实际工作。 该"闭包对象"是在执行时创建的,实际上,每次执行函数时都会创建一个新对象。
在您的案例中,将在执行foo()
时创建实际的闭包对象。 而且,事实上,每次执行它(并将返回值保存到变量中(时,都会创建一个新的闭包。 代码声明为闭包创造了机会,但在执行函数 foo
之前,不会创建实际的闭包本身。
以下是此代码中发生的情况:
function foo(i) {
function inner() {
return i;
}
return inner;
}
var f = foo(3);
var result = f();
首先声明 foo()
函数。 声明它返回对 inner()
函数的引用。 这为关闭设置了机会,但尚未创建关闭。
然后,当您执行 f = foo(3)
时,将执行函数foo
。 这将创建一个函数作用域对象(在解释器中(。 此函数 scope 对象中i
的参数在此特定执行foo
中具有 3
值,因此在此 scope 对象中也是如此。 当foo
执行时,它会返回对inner
的引用,然后将其分配给变量 f
。 因此,变量f
包含对inner()
的引用。
通常,当一个函数完成执行时,它的函数作用域对象会被垃圾回收(例如释放(,但在这种情况下,inner
仍然具有对该作用域对象的引用,并且f
包含对该inner
调用的引用。 因此,该范围对象不符合垃圾回收的条件,并保持活动状态。 这称为闭包。 因为存在的东西对函数作用域内的东西有引用,所以不能像往常一样对其进行垃圾回收。
定义函数的行为为闭包创造了机会,但实际的闭包是在每次运行foo()
时在执行时创建的。
事实上,如果你执行了f = foo(3)
,你创建了一个闭包,如果你执行g = foo(4)
,你又创建了一个闭包。 每次执行foo
并将返回值保存在变量中时,都会创建一个闭包。 请记住,这种类型的闭包实际上只是一个函数范围对象,无法立即进行垃圾回收,因为某些代码保留了对该函数作用域中对象的引用,超出了函数本身的生存期。
就我个人而言,当我真的只是从垃圾收集器的角度考虑它们时,闭包更容易理解。 它们只是函数范围对象(所有函数都有(,还不能被垃圾回收,因为某些代码保留了对其中某些内容的引用。 而且,创建此类闭包的最常见方法是当外部代码被赋予对父函数内部本地函数的引用时。
当 JS 创建一个函数时,它会将其 scope 属性设置为等于当前环境:http://ecma-international.org/ecma-262/5.1/#sec-13.2
当JS执行一个函数时,它会创建一个新环境,并将其"外部"(=parent(指针设置为函数的作用域:http://ecma-international.org/ecma-262/5.1/#sec-10.4.3
所以你的问题的答案是:闭包是在定义函数时创建的,而不是在调用时创建的。为了澄清,每次程序到达"函数"行时都会创建函数对象。如果调用外部函数两次,将有两个不同的函数对象(具有两个不同的 [[作用域]](。
闭包是一对 a( 函数的代码和 b( 调用帧链。调用帧本质上是包含局部变量和参数的结构。
因此,当您返回该inner
函数时,您将返回如下内容:
struct Function {
var functionBody; // compiled function body
var outerScopeChain = { i:3,
nextScope: null };
};
JS中的每个函数对象实际上都是一个闭包,outerScopeChain
全局函数为空。
- 使用JSTree上下文菜单捕获新创建的节点
- TinyMCE 在上下文菜单中创建子菜单
- 如何创建一个原型函数,将另一个原型函数绑定为语法糖(并保持实例的上下文)
- 如何根据单击的对象在右键单击时创建多个上下文菜单
- 如何创建菜单项根据运行时值更改的 html 上下文菜单
- 使用 bind 强制创建原型函数的上下文
- 将画布上下文插入到动态创建的新窗口 html 中的 html 字符串
- 如何创建一个上下文菜单,该菜单仅在单击容器时显示在光标位置上
- 为什么此处未创建执行上下文
- 是否可以将从画布上下文创建的渐变应用于其他画布上下文
- 如何使用从音频上下文创建的分析器来检测播放的声音是否可听
- 创建上下文菜单
- 无法隐藏由jeegoucontext创建的上下文菜单
- 我可以复制$吗?这样它在创建jQuery对象时总是使用上下文
- 在未按预期工作的文档上右键单击(上下文菜单)事件上创建弹出式菜单
- 为什么在动态创建的画布上下文不工作
- 创建上下文菜单上的单一点击
- 为什么我不能设置上下文.在我创建我的画布后立即填充样式
- 如何代理通过jQuery.find()在函数中创建的每个元素的上下文
- 为除某些网站外的所有网站创建上下文菜单条目