2014-02-21 55 views
9

我讀到有關如何circular references cause memory leaks in IE,但我用封內的封閉打破循環引用是上一個例子很困惑:雙閉合件如何打破循環引用?

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

我的頭把所有發生了口角與要什麼有什麼,這是關閉引用,這是範圍對象。有人能比MDN更明確地分解它嗎?謝謝。

回答

8

如果你有

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

然後elclickHandler的引用,但clickHandler也有el參考,因爲它是一個封閉。 ->循環引用(在IE)

通過引入新的範圍,你讓el當地,所以它通過clickHandler->沒有循環引用不可訪問。

function addHandler() { 
    var clickHandler = function() { 
     this.style.backgroundColor = 'red'; 
     // cannot access `el` here 
    }; 
    (function() { 
     // `el` is local to this immediately invoked function 
     var el = document.getElementById('el'); 
     el.onclick = clickHandler; 
    })(); 
} 

所以,解決了內存泄漏問題是引入又一封閉,它是在創建一個新範圍,即彼此「屏蔽」的值(在一個方向上最小)。

+0

所以在第一個例子中,即使'el'沒有在'clickHandler'中明確引用,'el'仍然存在於'clickHandler'的作用域對象中?意思是,儘管'clickHandler' *可以引用'el','clickHandler'可以訪問帶有或不帶有明確引用的'el'引用?因此,在'clickHandler'的作用域對象的'el'和'el'對象的'clickHandler'之間創建循環引用?我只是想確保''clickHandler'中的'this'語句不會引起對'el'的循環引用,而不是引用該引用的範圍對象。 –

+1

@TriNoensie:不,它與'this'無關。當一個函數被創建時,它也會獲得對該函數創建的「範圍」的引用,即它對所有在其創建的範圍中都可訪問的變量具有*隱式*引用。這在IE中引起了問題。 –

3

,我去的經驗法則:

對於JavaScript閉包被創建,必須有嵌套功能和內在功能必須能夠訪問或refered由(讓我們只說「觸摸」簡稱)外部函數中的變量。如果找不到這兩個標準中的任何一個,那麼JavaScript中就沒有關閉。

當外部函數中的這種變量(在上面的段落中提到)碰巧是一個DOM元素時,會發生內存泄漏。

在Mozilla文章,讓我們訪問的第一個例子:

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

顯然,嵌套在另一個函數內的一個功能,並且內功能被分配給一個變量的屬性(EL)在外部範圍內,所以創建了一個閉包。這個變量el也恰好是一個DOM元素,因此存在內存泄漏,正如文章中所解釋的那樣。

在您發佈第二個例子中,

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

有外功能,並且嵌套在這個外函數內部是2嵌套(內)的功能,但它們是在同一水平,這意味着一個不是嵌套在另一個裏面。第二個嵌套函數還可以訪問外部函數中的局部變量(clickHandler),因此會創建一個閉包。但是,沒有內存泄漏,因爲外部函數中的此局部變量(clickHandler)不是DOM元素。局部變量el不會導致內存泄漏,因爲它在第二個嵌套函數中是本地的,並且未在外部函數addHandler()中定義。換句話說,它在第二個嵌套函數中是局部的,它不能被第一個嵌套函數訪問,因此沒有內存泄漏的機會。