2010.02.28 Sunday
以前のエントリ([JavaScript]僕、スコープとかクロージャとか曖昧でした
)で書いた、Javascript のクロージャの話と全く同じことなのですが、あれをjQuery のclick イベントで書くとどうなるかということを、自分用にメモとして残しておきたいと思います。
例えば、div でブロックを3つ作って、それぞれにclick イベントを持たせるとします。そのとき、そのclick に反応して、そのblock が何番目に作られたものなのかをalert するようにしたいとします。
jQuery の.click は第一引数にコールバック関数をとるので、クロージャのことを意識せずに直感的に書くと、次のようなコードになるのではないでしょうか。
普段からJavascript を書いているかたであれば、すぐに問題点に気付くと思います。これは例の通り、click me - [i] のところのi は正しくその番号のものが表示されるのですが、実際にそれをクリックしてみても、alert で表示されるi は目的のものとは違うはずです。ここでも前回見た通り、「関数を返す無名関数をすぐに実行する」という方法で対応できます。
考え方としては、まず、「関数を返す無名関数を『すぐに実行する』」というところが重要なので、.click の引数にあたるところで、関数をすぐに実行させます。順を追って書くと、まずこんな感じになります。
当然、このfunction はすぐに実行されるのですが、.click は引数にコールバック関数をとるものなので、この実行される関数がそのコールバック関数を返さなければなりません。つまり、こう書くことになります。
そして、その中に書かれた返されるコールバック関数のところに目的のコードを書くことになります。
ここで、alert(_i) と書いたのですが、この_i は外側のfor のi とは別物ということをはっきりさせるために_i と書くことにしました。つぎに、この_i に外側のfor でまわされているi を渡したすというのを表現します。
すぐに実行される無名関数に、引数として i をとれるようにしました。ここでは、紛らわしくないように別の変数名(例えばn)を使ってつぎように書くこともできます。この方がi の違いを区別しやすくなるので、わかりやすいというかたもいらっしゃるかもしれません。
これで目的のclick イベントは完成です。jQuery のイベントに渡すコールバック関数では、引数にevent そのものをとることができます。このような書き方をした場合、それはこの内側に書いたコールバック関数で受取れます。次のe のような書き方です(今回の例ではこのe を使うことはありませんが)。
以上を踏まえて、最初に書いたものを書き直すと、以下のようになります。
僕もまだまだ初学者の域をでておりませんので、上記のような思考のもとに書いております。
)で書いた、Javascript のクロージャの話と全く同じことなのですが、あれをjQuery のclick イベントで書くとどうなるかということを、自分用にメモとして残しておきたいと思います。
例えば、div でブロックを3つ作って、それぞれにclick イベントを持たせるとします。そのとき、そのclick に反応して、そのblock が何番目に作られたものなのかをalert するようにしたいとします。
jQuery の.click は第一引数にコールバック関数をとるので、クロージャのことを意識せずに直感的に書くと、次のようなコードになるのではないでしょうか。
var div;
var i;
for(i=0; i<3; i++) {
div = $('<div/>').click( function( e ) {
alert(i)
} );
div.html('click me - ' + i);
div.css('cursor', 'pointer');
$('body').append(div);
}
普段からJavascript を書いているかたであれば、すぐに問題点に気付くと思います。これは例の通り、click me - [i] のところのi は正しくその番号のものが表示されるのですが、実際にそれをクリックしてみても、alert で表示されるi は目的のものとは違うはずです。ここでも前回見た通り、「関数を返す無名関数をすぐに実行する」という方法で対応できます。
考え方としては、まず、「関数を返す無名関数を『すぐに実行する』」というところが重要なので、.click の引数にあたるところで、関数をすぐに実行させます。順を追って書くと、まずこんな感じになります。
.click( function () {} () );当然、このfunction はすぐに実行されるのですが、.click は引数にコールバック関数をとるものなので、この実行される関数がそのコールバック関数を返さなければなりません。つまり、こう書くことになります。
.click( function () {
return function() {};
}() );そして、その中に書かれた返されるコールバック関数のところに目的のコードを書くことになります。
.click( function () {
return function() {
alert(_i);
};
}() );ここで、alert(_i) と書いたのですが、この_i は外側のfor のi とは別物ということをはっきりさせるために_i と書くことにしました。つぎに、この_i に外側のfor でまわされているi を渡したすというのを表現します。
.click( function (i) {
var _i = i;
return function() {
alert(_i);
};
}(i) );すぐに実行される無名関数に、引数として i をとれるようにしました。ここでは、紛らわしくないように別の変数名(例えばn)を使ってつぎように書くこともできます。この方がi の違いを区別しやすくなるので、わかりやすいというかたもいらっしゃるかもしれません。
.click( function (n) {
var _i = n;
return function() {
alert(_i);
};
}(i) );これで目的のclick イベントは完成です。jQuery のイベントに渡すコールバック関数では、引数にevent そのものをとることができます。このような書き方をした場合、それはこの内側に書いたコールバック関数で受取れます。次のe のような書き方です(今回の例ではこのe を使うことはありませんが)。
.click( function (n) {
var _i = n;
return function(e) {
alert(_i);
};
}(i) );以上を踏まえて、最初に書いたものを書き直すと、以下のようになります。
var div;
var i
for(i=0; i<3; i++) {
div = $('<div/>') .click( function( i ) {
var _i = i;
return function(e) {
alert(_i);
};
}(i) );
div.html('click me - ' + i);
div.css('cursor', 'pointer');
$('body').append(div);
}
僕もまだまだ初学者の域をでておりませんので、上記のような思考のもとに書いております。