我是一个javascript新手。我最近在学习javascript及其很好的财产关闭。
但是我对以下代码段感到困惑。
function outerFn() {
var outerVar = {};
function innerFn() {
alert('haha');
}
outerVar.pro = innerFn;
return innerFn;
}
我认为它不是innerFn和outerVar之间的循环引用,因为只有outerVar pro指向innerFn。
但有些书指出它仍然是循环参考。
有人可以解释它是否是循环引用? 提前谢谢。
答案 0 :(得分:1)
此可能在JavaScript 引擎中导致循环引用(因为innerFn
的父词法环境包括outerVal
,其中包含{{ 1}}),但不会导致JavaScript代码可以观察到循环引用。
运行innerFn
时,定义了函数outerFn
。在JavaScript中,新定义的函数可以访问当前在范围内可访问的所有变量,因此innerFn
内的代码可以访问innerFn
:
outerVar
在ECMAScript术语中,这是因为每个函数都有一个词汇环境,用于解析名为function outerFn() {
var outerVar = {};
function innerFn() {
alert(outerVar); // totally fine
}
return innerFn;
}
的变量标识符。新定义的函数的[[Scope]]
内部属性设置为其父函数的词法环境。因此,此处[[Scope]]
[[Scope]]
是innerFn
的词汇环境,其中包含对outerFn
的引用。
在ECMAScript术语中,循环引用路径为:
outerFn
innerFn
的{{3}}(a[[Scope]]
)innerFn
的{{1}}的{{3}}innerFn
[[Scope]]
的{{1}}环境记录中的outerVar
约束- 与
innerFn
[[Scope]]
的环境记录中的outerVar
绑定相关联的变量- 此变量的
innerFn
为属性值
但是,由于您无法从JavaScript代码访问函数的[[Scope]]
内部属性,因此无法从代码中观察循环引用。
请注意,一个聪明的实现不会实际在您的代码中存储此循环引用,因为它看到innerFn
从未在任何[[Scope]]
的子函数中使用。当outerVar
结束时,可以安全地忘记outerFn
的绑定。值得注意的是,outerVar
无法进行此优化,因为无法识别outerFn
是否会使用eval
:
innerFn