我是一个 JavaScript 新手。我最近正在学习 javascript 及其出色的属性闭包。
但是我对下面的代码片段感到困惑。
function outerFn() {
var outerVar = {};
function innerFn() {
alert('haha');
}
outerVar.pro = innerFn;
return innerFn;
}
我认为innerFn和outerVar之间不是循环引用,因为只有outerVar pro指向innerFn。
但是有些书指出它仍然是循环引用。
谁能解释一下这是否是循环引用? 提前致谢。
最佳答案
这可能导致JavaScript引擎内出现循环引用(因为innerFn
的父词法环境包括outerVal
,其中包括 innerFn
),但它不会导致 JavaScript 代码可以观察到的循环引用。
当outerFn
运行时,函数innerFn
被定义。在 JavaScript 中,新定义的函数可以访问当前作用域内可访问的所有变量,因此 innerFn
内部的代码可以访问 outerVar
:
function outerFn() {
var outerVar = {};
function innerFn() {
alert(outerVar); // totally fine
}
return innerFn;
}
用 ECMAScript 术语来说,这是因为每个函数都有一个词法环境,用于解析称为 [[Scope]]
的变量标识符。新定义函数的 [[Scope]]
内部属性设置为其父函数的词法环境。因此,这里 innerFn
的 [[Scope]]
是 outerFn
的词法环境,其中包含对 outerFn< 的引用
.
用 ECMAScript 术语来说,循环引用路径是:
innerFn
innerFn
's[[Scope]]
(a lexical environment)innerFn
's[[Scope]]
's environment record- the
outerVar
binding ininnerFn
's[[Scope]]
's environment record- the variable associated with the
outerVar
binding ininnerFn
's[[Scope]]
's environment record- this variable has
innerFn
as a property value
但是,由于您无法从 JavaScript 代码访问函数的 [[Scope]]
内部属性,因此您无法从代码中观察到循环引用。
奖金信息
请注意,聪明的实现实际上不会在代码中存储此循环引用,因为它发现 outerVar
从未在任何 outerFn
中使用。 code> 的子函数。当 outerFn
结束时,可以安全地完全忘记 outerVar
的绑定(bind)。更有趣的是,使用 eval
无法进行这种优化,因为无法识别 innerFn
是否会使用 outerVar
:
function outerFn() {
var outerVar = {};
function innerFn(codeStr) {
alert(eval(codeStr)); // will `codeStr` ever be "outerVar"?
}
return innerFn;
}
关于javascript - 这种模式是否会导致闭包中的循环引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26256986/