値によって変数を匿名のJavaScript関数に渡す方法は?
-
05-07-2019 - |
質問
目的
サイト全体のページの一部のdivにイベントハンドラーを動的に割り当てたい。
マイメソッド
jQueryを使用して、選択したdivイベントのハンドラーとして匿名関数をバインドしています。
問題
このコードは、div名と関連URLの配列を繰り返し処理します。 div名は、バインディングターゲットの設定に使用されます。つまり、このdivイベントにこのイベントハンドラーをアタッチします。
イベントハンドラーは各divイベントに正常にバインドされますが、それらのイベントハンドラーによってトリガーされるアクションは、配列の最後のアイテムのみをターゲットにします。
つまり、ユーザーが特定のdivにマウスを重ねると、そのdivのスライドアウトアニメーションを実行するという考え方です。ただし、代わりに、div1(rangeTabAll)にマウスを合わせると、div4(rangeTabThm)のスライドアウトアニメーションがトリガーされます。 div 2、3などにも同じことが言えます。順序は重要ではありません。周囲の配列要素を変更すると、イベントは常に配列の最後の要素div4をターゲットにします。
マイコード-(jQueryを使用)
var curTab, curDiv;
var inlineRangeNavUrls=[['rangeTabAll','range_all.html'],['rangeTabRem','range_remedial.html'],
['rangeTabGym','range_gym.html'],['rangeTabThm','range_thermal.html']];
for (var i=0;i<inlineRangeNavUrls.length;i++)
{
curTab=(inlineRangeNavUrls[i][0]).toString();
curDiv='#' + curTab;
if ($(curDiv).length)
{
$(curDiv).bind("mouseover", function(){showHideRangeSlidingTabs(curTab, true);} );
$(curDiv).bind("mouseout", function(){showHideRangeSlidingTabs(curTab, false);} );
}
}
私の理論
目もくらむほど明白な構文エラーも、参照による問題もありません。 最初は、curTabの値を設定する次のステートメントがありました。
curTab=inlineRangeNavUrls[i][0];
問題が発生したとき、curTabへの参照を(ループの繰り返しを介して)変更すると、実際には以前のすべての匿名関数イベントハンドラーの参照を新しいcurTabに変更していた値も同様です。これが、イベントハンドラーが常に最後のdivを対象とした理由です。
だから本当に必要なのは、curTab object 参照ではなく、curTab value を匿名関数イベントハンドラに渡すことです。
だから私は考えた:
curTab=(inlineRangeNavUrls[i][0]).toString();
問題は解決しますが、解決しません。同じ取引。したがって、明らかに、いくつかのキー、およびおそらく非常に基本的な問題に関する知識が欠けています。ありがとう。
解決
ループを通過するたびに新しい変数を作成する必要があります。これにより、イベントハンドラー用に作成しているクロージャーに変数がキャプチャされます。
ただし、変数宣言をループに移動するだけではこれを達成できません。これは、 JavaScriptは、任意のブロックに新しいスコープを導入しません。
新しいスコープの導入を強制する簡単な方法の1つは、別の匿名関数を使用することです:
for (var i=0;i<inlineRangeNavUrls.length;i++)
{
curDiv='#' + inlineRangeNavUrls[i][1];
if ($(curDiv).length)
{
(function(curTab)
{
$(curDiv).bind("mouseover", function(){showHideRangeSlidingTabs(curTab, true);} );
$(curDiv).bind("mouseout", function(){showHideRangeSlidingTabs(curTab, false);} );
})(inlineRangeNavUrls[i][0]); // pass as argument to anonymous function - this will introduce a new scope
}
}
As Jasonが提案する、jQueryの組み込み を使用して、実際にかなりきれいにすることができます。 hover()
関数:
for (var i=0;i<inlineRangeNavUrls.length;i++)
{
(function(curTab) // introduce a new scope
{
$('#' + inlineRangeNavUrls[i][1])
.hover(
function(){showHideRangeSlidingTabs(curTab, true);},
function(){showHideRangeSlidingTabs(curTab, false);}
);
// establish per-loop variable by passsing as argument to anonymous function
})(inlineRangeNavUrls[i][0]);
}
他のヒント
ここで起こっていることは、あなたの匿名関数がクロージャを形成し、それらの外側のスコープをそれらと一緒に持っているということです。つまり、匿名関数内でcurTabを参照する場合、イベントハンドラーがその関数を実行すると、外部スコープでcurTabの current 値が検索されます。これは、curTabに最後に割り当てたものです。 (関数をバインドしたときに割り当てられたものではありません)
これを変更する必要があります:
$(curDiv).bind("mouseover", function(){showHideRangeSlidingTabs(curTab, true);} );
これ:
$(curDiv).bind("mouseover",
(function (mylocalvariable) {
return function(){
showHideRangeSlidingTabs(mylocalvariable, true);
}
})(curTab)
);
これにより、curTabの値が外部関数のスコープにコピーされ、内部関数はそれを使用します。このコピーは、内部関数をイベントハンドラーにバインドするのと同時に行われるため、&quot; mylocalvariable&quot;その時点でのcurTabの値を反映します。次に、ループの次回に、新しいスコープを持つ新しい外部関数が作成され、curTabの次の値がそこにコピーされます。
shog9の答えは基本的に同じことを達成しますが、彼のコードはもう少し厳格です。
ちょっと複雑ですが、考えてみると意味があります。閉鎖は奇妙です。
edit:おっと、内部関数を返すのを忘れました。修正。
これを必要以上に複雑にしていると思います。マウスオーバー/アウトにスライド効果を割り当てるだけの場合は、ホバー jqueryによる効果。
$("#mytab").hover(function(){
$(this).next("div").slideDown("fast");},
function(){
$(this).next("div").slideUp("fast");
});
完全なHTMLを投稿した場合、その方法を正確に説明できます:)
変数の値を存在しないタグに入れて、後でそこから読み取ることができます。このスニペットはループ本体の一部です:
s = introduction.introductions[page * 6 + i][0]; //The variables content
$('#intro_img_'+i).attr('tag' , s); //Store them in a tag named tag
$('#intro_img_'+i).click( function() {introduction.selectTemplate(this, $(this).attr('tag'));} ); //retrieve the stored data