ブログが続かないわけ

この日記のはてなブックマーク数
Webエンジニアが思うこと by junichiro on Facebook

[JavaScript]jQuery のイベントとクロージャ

このエントリーを含むはてなブックマーク hateb

以前のエントリ([JavaScript]僕、スコープとかクロージャとか曖昧でした )で書いた、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);
}

僕もまだまだ初学者の域をでておりませんので、上記のような思考のもとに書いております。

この記事のトラックバックURL
http://en.yummy.stripper.jp/trackback/1353835
トラックバック
コメント









関連情報