【问题标题】:JavaScript memory leak explanationJavaScript 内存泄漏解释
【发布时间】:2012-02-09 08:56:17
【问题描述】:
function addHandler() {  
    var el = document.getElementById('el');  
    el.onclick = function() {  
        this.style.backgroundColor = 'red';  
    }  
}

上面的代码包含在Mozilla blog post on JavaScript 中,并指出上面的代码会导致内存泄漏。

有人可以解释一下吗:

因为对 el 的引用无意中被为匿名内部函数创建的闭包中捕获。这会在 JavaScript 对象(函数)和本机对象 (el) 之间创建循环引用。

谢谢!

【问题讨论】:

    标签: javascript browser


    【解决方案1】:

    根据我的解释,这本身并不是内存泄漏(有时如果没有这样的构造,您将无法解决问题,但它们要复杂得多),但这并不好,因为您创建了 onclick 函数每次都是新的,它保持与其父级的“链接”(闭包的作用)。这段代码会好很多;

    function clickHandler(){
        this.style.backgroundColor = 'red';
    }
    function addHandler() {  
        var el = document.getElementById('el');  
        el.onclick = clickHandler           
    }
    

    这样,不会创建闭包,不会进行未使用的引用,也不会多次生成函数。

    【讨论】:

    • 答案是,所有闭包在创建时都会保持与父级的链接。因此 onclick 闭包引用 el 又引用 el?
    • 在您的问题代码中,onclick 函数有一个指向其父级的链接,因此可以访问“el”变量。在函数内部,“el”变量等价于“this”,因此你有一个小圆圈。
    【解决方案2】:

    @thg435:看起来这可能是使用 eval 的结果。

    在 Firefox 或 Chrome 中使用foo 上的手表执行以下操作,同时在debugger 上中断报告 foo 的值未定义。

    (function () {
      var foo = "bar";
      return function() {
        debugger;
      };
    })()();
    

    在执行以下报告时,foo 的值为"bar",而在debugger 处中断:

    (function () {
      var foo = "bar";
      return function(_var) {
        debugger;
        return eval(_var);
      };
    })()('foo');
    

    如果能得到一个明确的答案,那就太好了。

    【讨论】:

      【解决方案3】:

      问题是:闭包是捕获当前范围内的所有变量还是仅捕获明确提及的变量?考虑:

      function makeClosure() {
         var foo = 1;
         var bar = ...some heavy object...
      
         return function() {
             do_something_with(foo)
         }
      }
      

      内部函数捕获foo,它是否也捕获bar?我想,是的,因为以下打印了正确的值:

      function makeClosure(bar) {
         var foo = 1;
      
         return function(name) {
             console.log(foo);
             console.log(eval(name));
      
         }
      }
      
      makeClosure('print_me')('bar')
      

      因此,在您的示例中,el 被“无意”捕获在闭包(onclick 处理程序)中。因此,闭包指的是elel.onclick 指的是闭包qed。

      【讨论】:

        猜你喜欢
        • 2011-12-08
        • 1970-01-01
        • 2012-06-08
        • 2012-11-21
        • 2011-02-28
        • 2014-10-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多