2012-02-09 166 views
2
function addHandler() { 
    var el = document.getElementById('el'); 
    el.onclick = function() { 
     this.style.backgroundColor = 'red'; 
    } 
} 

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

有人能解释它比:

由于厄尔尼诺参考无意中陷入了匿名内部函数创建关闭。这会在JavaScript对象(函数)和本机对象(el)之间创建循环引用。

谢谢!

回答

2

与我的解释,这不是一个memoryleak本身(有时你不能解决你的问题没有这样的构造,但他们更复杂),但它不好,因为你创建onclick每次新增功能时,都会保持与其父项的“连接”(关闭功能)。这个代码会好得多;

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

这种方式,没有创建闭合,未使用的引用是由无功能将被多次生成。

+0

答案是,当它们被创建时,所有关闭都会保持与父母的链接。因此'onclick'的闭包引用'el',它又引用'el'? – tgandrews 2012-02-09 09:05:38

+0

在你的问题代码,onclick函数有一个链接到其父,因此有权访问'el'变量。在函数内部,'el'变量等同于'this',因此你有一个小圆圈。 – japrescott 2012-02-09 09:13:16

0

问题是:闭包是捕获当前作用域中的所有变量还是仅捕获当前作用域中的所有变量?试想一下:

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处理程序)。因此,封闭指的是el,而el.onclick指的是关闭qed。

1

@ 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'); 

这将是巨大的,就在这一个明确的答案。