1. クロージャとは何か、およびクロージャに含まれるスコープ チェーンについてはここでは説明しません。
2. JavaScript ガベージ コレクション メカニズム
JavaScript は手動でメモリを解放する必要がなく、自動ガベージ コレクション メカニズム (ガベージ コレクション) を使用します。オブジェクトが役に立たない場合、つまりプログラム内の変数がそのオブジェクトを参照していない場合、その変数はメモリから解放されます。
var s = [1, 2,3];
var s = null;
//このようにして、元の配列 [1,2,3] が解放されます。
3. 循環参照
3 つのオブジェクト A、B、C
AàBàC: A のある属性が B を参照しており、C も B の属性によって参照されています。 A がクリアされると、B と C もリリースされます。
AàBàCàB: ここでは、B オブジェクトを参照するために C の特定の属性が追加されています。これが A をクリアする場合、B と C の間に循環参照が生成されるため、B と C は解放されません。
var a = {};
a.pro = { a:100 };
a.pro.pro = { b:100 };
a = null
//この場合、{a:100} と {b:100} も同時に解放されます。
var obj = {};
Obj.pro = { a : 100 };
Obj.pro.pro = { b : 200 };
var two = obj.pro.pro;
オブジェクト = null;
//この場合、{b:200} は解放されませんが、{a:100} は解放されます。
4. 循環参照とクロージャ
関数アウター(){
var obj = {};
関数 inner(){
//obj オブジェクトはここで参照されます
}
obj.inner = inner;
}
これは非常に隠された循環参照です。 external が一度呼び出されると、その中に obj と inner という 2 つのオブジェクトが作成されます。obj の inner プロパティは、同様に、innerFun の閉じた環境にあるためです。正確に言えば、これは JavaScript 独自の「スコープ チェーン」によるものです。
したがって、クロージャは循環参照を非常に簡単に作成できます。幸いなことに、JavaScript はそのような循環参照を非常にうまく処理できます。
5. IE のメモリリーク
IE にはいくつかの種類のメモリ リークがあり、詳細な説明はここ (
http://msdn.microsoft.com/en-us/library/bb250448.aspx
) にあります。
ここではそのうちの 1 つだけを説明します。つまり、循環参照によって引き起こされるメモリ リークです。これは最も一般的な状況であるためです。
DOM 要素または ActiveX オブジェクトと通常の JavaScript オブジェクトの間に循環参照がある場合、IE ではそのような変数を解放することが特に困難になります。このバグは IE で修正されています。 7 (
http://www.quirksmode.org/blog/archives/2006/04/ie_7_and_javasc.html
)。
「IE 6 では、少なくとも 1 つの DOM ノードを含む複数のオブジェクト間の循環参照が作成されると、メモリ リークが発生しました。この問題は IE 7 で解決されました。」
上記の例(ポイント4)で、objがJavaScript Functionオブジェクト(内部)ではなく、ActiveXオブジェクトやDom要素を参照している場合、IE内で形成された循環参照を解放できません。
コードをコピー コードは次のとおりです:
関数 init(){
var elem = document.getElementByid( 'id' );
elem.onclick = function(){
alert('雨男');
//elem 要素
はここで参照されます
};
}
Elem は、そのクリック イベント リスニング関数を参照します。また、そのスコープ チェーンを通じて elem 要素も参照します。このようにすると、IE で現在のページを離れても、これらの循環参照は解放されません。
6. 解決策
基本的な方法は、この循環参照を手動でクリアすることです。実際のアプリケーションでは、addEvent() 関数を自分で作成し、ウィンドウのアンロード イベントのすべてのイベント バインディングをクリアできます。
関数アウター(){
var one = document.getElementById( 'one' );
one.onclick = function(){};
}
window.onunload = function(){
var one = document.getElementById( 'one' );
one.onclick = null;
};
その他の方法 (作成者: Douglas Crockford)
/**
* 要素ノードとそのすべての子孫要素をトラバースします
*
* @param Elemノード クリアする要素ノード
* @param function func
を処理する関数
*
*/
function walkTheDOM(node, func) {
関数(ノード);
ノード = ノード.firstChild;
while (ノード) {
walkTheDOM(node, func)
ノード = ノード.nextSibling
}
}
/**
* メモリリークを防ぐために dom ノードへの参照をすべてクリアします
*
* @param Elemノード クリアする要素ノード
*
*/
function purgeEventHandlers(node) {
walkTheDOM(node, function (e) {
for (var n in e) {
If (typeof e[n] ===
'関数') {
e[n] = null;
}
}
});
上記は JavaScript のメモリ リークに関する関連コンテンツと解決策です。必要な場合は参照してください。