jQuery: JavaScriptでイベントハンドラに好きな値を渡す方法

他の言語に慣れていると、JavaScriptのスコープチェーンが分かりづらいですね。

たとえば、jQueryでクリックイベントに関数を登録する際、外の変数を参照すると予期せぬ結果になってしまうことがあります。

例:すべてのボタンで3が表示されてしまう

<html>
<head>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
$(function() {
    for (var i = 0; i < 3; i++) {
        $('#button' + i).click(function() {
            alert(i);
        });
    }
});
</script>
</head>
<body>
<button id="button0">0</button>
<button id="button1">1</button>
<button id="button2">2</button>
</body>
</html>

このような場合、以下のようにすることで、意図した動作が実現できます。

for (var i = 0; i < 3; i++) {
    $('#button' + i).click((function(i) {
        return function() {
            alert(i);
        }
    })(i));
}

しかし、毎回これをやるのも面倒なので、好きな引数を渡せるような関数を作ってしまうのも良いですね。
これなら可変長引数にもそのままで対応できます。

$.func = function() {
    var fn = arguments[arguments.length - 1];

    var arg = new Array(arguments.length - 1);
    for (var i = 0; i < arguments.length - 1; i++) {
        arg[i] = arguments[i];
    }

    return function() {
        fn.apply(this, arg);
    }
};

for (var i = 0; i < 3; i++) {
    $('#button' + i).click($.func(i, function(i) {
        alert(i);
    }));
}

jQueryにはdojo.hitch相当のものがないですが、これで似たようなことはできそうです。

追伸

4/17追記

jQuery1.4 で追加された jQuery.proxy が dojo.hitch 相当なので、これを使っても良かったですね。
まあお好みで・・・

というより、よく 1.3 までこの関数なしでやってきましたよね。必須だと思うのですが。

デザインも頼めるシステム開発会社をお探しならBPS株式会社までどうぞ 開発エンジニア積極採用中です! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

baba

ゆとりプログラマー。 高校時代から趣味でプログラミングを初め、そのままコードを書き続けて現在に至る。慶應義塾大学環境情報学部(SFC)卒業。BPS設立初期に在学中から参加している最古参メンバーの一人。Ruby on Rails、PHP、Androidアプリ、Windows/Macアプリ、超縦書の開発などを気まぐれにやる。軽度の資格マニアで、情報処理技術者試験(16区分17回 + 情報処理安全確保支援士試験)、技術士(情報工学部門)、Ruby Programmer Gold、AWSソリューションアーキテクト(アソシエイト)、日商簿記2級、漢検準1級などを保有。

babaの書いた記事

週刊Railsウォッチ

インフラ

ActiveSupport探訪シリーズ

BPSアドベントカレンダー