闭包

11 小时前
/ ,
2

闭包

概念

闭包指 函数 + 函数声明时所在的作用域内、仍被该函数引用着的自由变量,即使创建函数的上下文已经销毁,函数和变量仍然存在。

var scope = "global scope";
function checkscope(){  //checkscopeContext.AO
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f;
}

var foo = checkscope();
foo();

当 checkscope() 执行时,引擎为它的局部变量 scope="local scope" 创建一份活动对象(checkscopeContext.AO)。函数 f 在内部被创建,内部记录了对外层 checkscopeContext.AO 的引用([[Environment]] 指针)。 checkscope() 返回 f 并结束,正常情况下它的 checkscopeContext.AO 该被垃圾回收,但因为 f 仍拿着指向该 AO 的引用,引擎保留这份 checkscopeContext.AO——这就是闭包。变量 foo 拿到 f 后,在任何地方调用 foo(),都会沿着 f 保存的引用找到那份早已死亡的 AO,从而读出 "local scope"。就是因为这个作用域链,f 函数依然可以读取到 checkscopeContext.AO 的值。

说明当 f 函数引用了 checkscopeContext.AO 中的值的时候,即使 checkscopeContext 被销毁了,但是 JavaScript 依然会让 checkscopeContext.AO 活在内存中,f 函数依然可以通过 f 函数的作用域链找到它,正是因为 JavaScript 做到了这一点,从而实现了闭包这个概念

闭包与内存泄漏

闭包所保留下来的词法作用域,本质是由于外部自由变量的引用仍然可达,GC无法做到清理这块作用域链,虽然引用的变量可能很少,但是由于关联的词法作用域拥有的数量庞大,导致内存泄漏的风险扩大,不可控加剧。

措施

  • 词法作用域中的变量不再使用时,将其置为 null,便于垃圾回收标记。
  • 创建监听器和timer时不要忘记调用remove和clear方法。
  • 全局变量相当于在整个生命周期中滞留的内存变量,谨慎使用。
  • 不要遇事不决就函数套函数。

使用社交账号登录

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...