请注意下面的闭包示例:
<script>
function foo() {
var x = 1;
function bar() {
var y = 2;
alert(x + y);
}
return bar;
}
var dummy = foo(); // Assign variable binding "dummy" to a reference of the "bar" function.
dummy(); // When entering the "bar" function code, will it go through the execution context creation phase?
</script>
当调用虚拟变量绑定(将执行“bar”功能代码)时,是否创建了新的执行上下文? ECMAScript规范指定entering function code时会发生什么,但由于这是对函数/闭包的引用,我不确定它是否必须再次完成整个执行上下文创建/绑定阶段。
答案 0 :(得分:2)
好问题。让我们看看发生了什么:
dummy()
是Function Call (11.2.3)
参见步骤#8 “返回在func上调用[[Call]]内部方法的结果,提供thisValue作为此值并提供列表argList作为参数值。”
因此调用了dummy.[[Call]]
。转到13.2.1([[Call]]
)。
让funcCtx是使用F的[[FormalParameters]]内部属性的值,传递的参数List args以及10.4.3中描述的该值为函数代码建立新的执行上下文的结果。
所以dummy()
确实创建了新的执行上下文,如10.4.3中所述。
现在执行dummy
的功能代码,按照10.4.3传递dummy.[[Scope]]
dummy
只是对bar
的引用,因此dummy.[[Scope]]
为bar.[[Scope]]
。并且bar.[[Scope]]
在执行foo
时被定义(前一行),自然地为每个函数声明创建函数(包括bar
)。
bar.[[Scope]]
本质上是由[global environment]
和[foo VE]
(变量环境)组成的链。所以在它执行的那一刻它创建了自己的VE并使用foo的VE作为外部。范围链现在由[global environment]->[foo VE]->[bar VE]
组成。
x
,在条形图的VE中找到y
,并且警报成功接收3
作为参数:)
但是要回答你原来的问题,是的“输入功能代码”会发生在
的情况下(function(){ ... })();
以及
的情况f();
因为它们都基本上调用函数[[Call]]。只有第一个是CallExpression
,其中FunctionExpression
后跟Arguments
,而第二个是CallExpression
,其中包含Identifier
后跟{Arguments
1}}。
两者仍然解析为一个函数对象,它具有内部[[Call]]方法,这是执行的方法。
答案 1 :(得分:0)
我认为范围链是你在这里看到的东西:
每次调用一个函数时,它都会创建一个新对象来存储其局部变量,并将该新对象添加到存储的作用域链中,以创建一个新的,更长的链,表示该函数调用的作用域。
对于你的问题是,它将再次通过整个执行上下文,否则如何从bar()返回另一个函数,如
function bar() {
var y = 2;
alert(x + y);
return function() {alert('hello');}
}