2012-02-09 119 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'); 

這將是巨大的,就在這一個明確的答案。