人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

addEventListener()に指定する無名関数に、引数を変数で渡したい

以下の関数 addListener4Element は、load後に、loadイベントリスナーに登録します。
この関数内で、3つのターゲット要素 elem1, elem2, elem3 にmouseoverイベントリスナーを
登録していますが、
関数内で使用されている 変数 i をイベントリスナーの引数として渡したいと
思っています。
function addListener4Element() {

var elem1 = document.getElementById("target1");
var elem2 = document.getElementById("target2");
var elem3 = document.getElementById("target3");

for (var i=1; i <= 3; i++) {

if (eval("elem"+i).attachEvent){
eval("elem"+i).attachEvent('onmouseover', function(){ showPopupElement(i);});
}
else if (eval("elem"+i).addEventListener){
eval("elem"+i).addEventListener('mouseover', function(){ showPopupElement(i);}, false);
}
}
}

function showPopupElement(num) {
console.debug(num)
/* 省略 */
}

しかし、関数 showPopupElement にconsole.debug を仕込ませて、引数 i の値をFirebug
で確認しました。各3つの要素にマウスを当てて、値を確認しましたら、
いずれの要素でも値は、4 しか渡されません。

それぞれ3つのmouseoverイベントリスナーに、順番に 1,2,3 の値を渡すには、どのように
したら良いでしょうか?

●質問者: gdwtseq
●カテゴリ:ウェブ制作
○ 状態 :終了
└ 回答数 : 1/1件

▽最新の回答へ

1 ● a-kuma3
●200ポイント ベストアンサー

以下のくだりを、

eval("elem"+i).addEventListener('mouseover', function(){ showPopupElement(i);}, false);

こんな感じに変更です。

var f = (function() {
 var ii = i;
 return function(){ showPopupElement(ii);}
 })();
eval("elem"+i).addEventListener('mouseover', f, false);

分りやすいように、変数 f を使ってますが、addEventListener の引数に直接書いても OK です。


それをふまえて、三回ループする部分が、こうなります。

for (var i=1; i <= 3; i++) {

 var f = (function() {
 var ii = i;
 return function(){ showPopupElement(ii);}
 })();

 if (eval("elem"+i).attachEvent){
 eval("elem"+i).attachEvent('onmouseover', f);
 }
 else if (eval("elem"+i).addEventListener){
 eval("elem"+i).addEventListener('mouseover', f, false);
 }
}

gdwtseqさんのコメント
早速のご回答ありがとうございます。 ご丁寧に提示頂いた方法で解決しました! 当方、Javascript の基礎がまだ身に付いておらず、 何をやっているのか理解できませんが、 これはハックと言われるやり方なのでしょうか? おもしろくもあるし、また、遠回しな方法だなぁとも感じます。

a-kuma3さんのコメント
>> これはハックと言われるやり方なのでしょうか? << 「ハック」と言うと、明文化されていないものを、ほじくりだした、というようなニュアンスがありますが、ぼくが示したのは規格で定められている範囲内です。 javascript の関数(というか、関数オブジェクト)が、クロージャと呼ばれる由縁です。 "javascript スコープチェーン" という感じのキーワードで探すと、いろいろ情報が引っかかります。 質問のコードだと、変数 i のスコープが三回のループにあるので、そこで変更された結果が、それを参照しているところ(イベントハンドラ)にも及びます。 ぼくが回答したコードでは、変数 ii は、変数 f に関数オブジェクトを返す無名関数のスコープにあるので、無名関数が返す関数オブジェクトの数だけスコープがあり、その時点の値が保持されます。 # んー、あまり説明になってないかな…

gdwtseqさんのコメント
ご返信ありがとうございます。 「クロージャ」は参考書で読んだことはありましたが、よく理解が出来ませんでした。しかし、今回のアドバイスで少し理解が進むのではないかと思っています。 ご丁寧なご説明をありがとうございました。
関連質問

●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ