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 の値を渡すには、どのように
したら良いでしょうか?

回答の条件
  • 1人5回まで
  • 13歳以上
  • 登録:2012/07/23 17:04:10
  • 終了:2012/07/26 17:10:07

ベストアンサー

id:a-kuma3 No.1

a-kuma3回答回数4468ベストアンサー獲得回数18432012/07/23 17:20:36

ポイント200pt

以下のくだりを、

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);
    }
}
他1件のコメントを見る
id:a-kuma3

これはハックと言われるやり方なのでしょうか?

「ハック」と言うと、明文化されていないものを、ほじくりだした、というようなニュアンスがありますが、ぼくが示したのは規格で定められている範囲内です。

javascript の関数(というか、関数オブジェクト)が、クロージャと呼ばれる由縁です。
"javascript スコープチェーン" という感じのキーワードで探すと、いろいろ情報が引っかかります。

質問のコードだと、変数 i のスコープが三回のループにあるので、そこで変更された結果が、それを参照しているところ(イベントハンドラ)にも及びます。

ぼくが回答したコードでは、変数 ii は、変数 f に関数オブジェクトを返す無名関数のスコープにあるので、無名関数が返す関数オブジェクトの数だけスコープがあり、その時点の値が保持されます。

# んー、あまり説明になってないかな…

2012/07/23 20:36:27
id:gdwtseq

ご返信ありがとうございます。

「クロージャ」は参考書で読んだことはありましたが、よく理解が出来ませんでした。しかし、今回のアドバイスで少し理解が進むのではないかと思っています。

ご丁寧なご説明をありがとうございました。

2012/07/26 17:09:50

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません