Introduction

ブログ内検索

  • このサイトの記事を検索 by Google

おすすめの一冊!

無料ブログはココログ

« Twitter はじめました | トップページ | ついったー用語 »

2009-09-01

クロージャーでつまらないミス

JavaScript (GreaseMonkey) を書いていて、
つまらないミスをしてしまったので、メモ。


いくつか並んでいる HTML 要素にそれぞれイベントリスナーを設定する場合、
for ループで addEventListener() を呼ぶことがあると思います。
そのとき、イベントリスナーとして無名関数を使うと、ちょっと罠にはまる
可能性があります。

たとえば、こんなコードを書いちゃったり ↓

var list = ['a', 'b', 'c']; for (var i=0; i<list.length; i++) { button[i].addEventListener( 'click', function() { alert(list[i]); }, false ); }
このコードはたぶん期待した動きをしません。 ボタンを押しても "undefined" という値が表示されるハズです。 なぜかというと、無名関数の中で変数 i を参照しているからです。 変数 i は関数の外のスコープにあるのでクロージャーとなりますが、 変数 i はイベントリスナーを登録した時点でインクリメントされて しまうため、コールバックされたときには i=3 になっているのです。 正攻法でやるなら、イベントリスナーごとにスコープを作ってあげて 変数 i の値をコピーしておいてあげる必要があります。
var list = ['a', 'b', 'c']; for (var i=0; i<list.length; i++) { (function() { var id = i; button[i].addEventListener( 'click', function() { alert(list[id]); }, false ); })(); }
冷静に考えれば当たり前のことなんですけど、 実際に書いたコードが正しく動かなくて、 ちょっと悩んでしまいました。 クロージャー+無名関数の組み合わせは強力で便利なのですが、 けっこう落とし穴あるので要注意かも。

« Twitter はじめました | トップページ | ついったー用語 »