おとといの日記に書いた、「色々と調べたいこと」について今日も調べた。
なんとか結果をまとめてみた。
(1)currentTargetとsrcElementの違いevent.target と window.event.srcElement は同じ要素を指す。(window.eventはIEのみ)
event.target はイベントが発生した要素を、event.currentTarget はイベントリスナをセットした要素を指す。
リスナをセットした要素が子孫要素を持っていなければ、event.currentTarget と event.target は同じ要素を指す。
<event.currentTarget と event.targetが異なる例>
<body onload="init()">
<div id="DIV"><button id="BUTTON">click</button></div>
<body>
において、
function showevent(evt){
var msg = "event.target.id=" + evt.target.id + "\n" +
"event.currentTarget.id=" + evt.currentTarget.id;
alert(msg);
}
function init(){
var elm = document.getElementById("DIV");
elm.addEventListener("click", showevent, false);
}
のようにして<div>にイベントリスナをセットした場合、
<button>をクリックすると
event.target.id=BUTTON
event.currentTarget.id=DIV
と表示される。
(2)クロージャとは?参考資料:
猿でもわかるクロージャ超入門 まとめJavaScriptでは、関数内で定義された内部関数は、外側の関数のローカル変数を参照できる。
そのような内部関数をクロージャと呼ぶ。
例)
function outer(){
var x = 1; // outerのスコープ内で変数を定義
return function (){ //この関数が「クロージャ」
alert(x); // "関数内関数"の中で、outerスコープの変数を参照。
x = x + 1;
};
}
outer() が実行されるたびに、無名関数 function (){alert(x);x = x + 1;} および無名関数が参照する変数xが生成される。
この変数xは保持される。
var f1 = outer(); // function (){alert(x);x = x + 1;} のオブジェクトと変数xが生成&初期化される。x = 1
f1(); // "1"をalert後、x = x + 1 が実行される。x = 2
f1(); // "2"をalert後、x = x + 1 が実行される。x = 3
var f2 = outer(); // function (){alert(x);x = x + 1;} のオブジェクトと変数xが生成&初期化される。x = 1
f2(); // "1"をalert後、x = x + 1 が実行される。x = 2
f1(); // "3"をalert後、x = x + 1 が実行される。x = 4
f1とf2は異なるオブジェクトのため、変数xも別々に生成される。
(3)無名関数を使用する場合のメモリ消費問題参考資料:
element.addEventListener - MDC -イベントリスナをセットする際に無名関数を使用する。
例)
var listener = function(){jsObj.init();}
window.addEventListener("load", listener, false);
この場合、jsObjだけでなく、無名関数 function(){jsObj.init();} がアクセス可能な全ての変数がメモリに保持される。
removeEventListener を呼び出すか無名関数への参照を全て削除すれば、変数の消費するメモリが解放されるようになる。
(4)無名関数使用とIE循環参照の関係参考資料:
Internet Explorer リーク パターンを理解して解決する無名関数等でクロージャを作成し、クロージャをイベントとして要素にセットする
例)
function AttachEvents(element){
// クロージャ作成
var listener = function(){ClickEventHandler.call(element)}
element.attachEvent("onclick", listener);
}
function ClickEventHandler(){
// thisでイベント発生元要素を取得
}
function SetupLeak(){
AttachEvents(document.getElementById("LeakedDiv"));
}
イベントセットにより、id="LeakedDiv" の要素 → クロージャ function(){ClickEventHandler.call(element)} の参照が発生。
クロージャは定義元の関数への参照を保持するので、 クロージャ → element → id="LeakedDiv" の要素
という参照も発生し、循環参照となってメモリリークが発生する。
自分が理解できる程度にはまとめられたが、分かり易いかどうか客観的に判定できない。
間違って理解しているところもあるかもしれない。