此模式是否会导致闭包中的循环引用?

时间:2014-10-08 12:32:15

标签: javascript closures circular-reference

我是一个javascript新手。我最近在学习javascript及其很好的财产关闭。

但是我对以下代码段感到困惑。

function outerFn() {
  var outerVar = {};
  function innerFn() {
    alert('haha');
  }
  outerVar.pro = innerFn;
  return innerFn;
}

我认为它不是innerFn和outerVar之间的循环引用,因为只有outerVar pro指向innerFn。

但有些书指出它仍然是循环参考。

有人可以解释它是否是循环引用? 提前谢谢。

1 个答案:

答案 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