2011-09-10 4 views
2

私はアンカーオブジェクトにハンドラを追加するために匿名関数を使用しようとしています。なぜこのコードは匿名関数を使用して動作していません

私はこのコードを実行しますが、うまくいかない理由を説明して修正することはできますか?ありがとう:

var obj = document.getElementsByTagName("a"); 
var items = ["mouseover", "mouseout"]; 
for (var i = 0; i < items.length; i++) { 
    (function() { 
     var item = items[i]; 
     for (var i = 0; i < obj.length; i++) { 
      obj[i]["on" + item] = function() { 
       alert("thanks for your " + item); 
      };  
     } 
    })();    
} 
+2

期待どおりの結果と何が効果がありませんか? – ajreal

+2

なぜあなたは無名関数を使用しますか?この場合、これはまったく意味がありません。ただそれを削除します。 – Tomalak

+1

*有効ではありません*は有用な問題の説明ではありません。とにかく、いくつかの問題があります:ネストされたループは、同じループ変数を使用し、新しいスコープを作成せずにループ内にクロージャを作成します。 –

答えて

7

は "ホイスト"です。言い換えれば、あなたの関数は、として実行されている:items[i]でそう

var i; 
var item; // vars are hoisted to the beginning 

item = items[i]; 
for (i = 0; i < obj.length; i++) { 
    obj[i]["on" + item] = function() { 
     alert("thanks for your " + item); 
    };  
} 

iは外側iに言及されていません。代わりに、iundefinedです。別の変数名を使用する必要があります。 j内側のforループ:

for (j = 0; j < obj.length; j++) { 

第二に、itemは警告が毎回同じ値を使用しますので、変更されます。これを回避するには、無名関数を使用することができますが、それらのポイントは、それが「フリーズ」するように値を渡すことです:

var obj = document.getElementsByTagName("a"); 
var items = ["mouseover", "mouseout"]; 
for (var i = 0; i < items.length; i++) { 
    var item = items[i]; 

    (function(item) { 
     for (var j = 0; j < obj.length; j++) { 
      obj[j]["on" + item] = function() { 
       alert("thanks for your " + item); 
      };  
     } 
    })(item);    
} 
+0

彼はまだ外側のループから値を "取り込む"必要があります... –

+3

@Felix Kling:内部ループに 'j'を使用すると' i'はホイストされていないので正しい値を持ちます。安全に捕獲する。 – pimvdb

+3

Ah true ....それでも、 'item';)を"捕捉 "する必要があります(そうでなければ、' alert'はすべてのハンドラ(少なくとも外側ループの反復ごとに作成されたもの)のために同じものを出力します)。 –

5

理由は、それが割り当てられている前に、変数を使用していることです値:

var item = items[i]; 

変数iは、次の行にsurrondingスコープからではない変数を宣言されたローカル変数です。変数は関数スコープを持っているので、変数が次の行で宣言されても、関数全体に存在します。

周囲のスコープから変数にアクセスできるようにするには、関数の変数に別の名前を使用する必要があります。歴史的な理由から、ループ変数は通常、必要に応じてi、j、kという名前になります。

var obj = document.getElementsByTagName("a"); 
var items = ["mouseover", "mouseout"]; 
for (var i = 0; i < items.length; i++) { 
    (function() { 
    var item = items[i]; 
    for (var j = 0; j < obj.length; j++) { 
     obj[j]["on" + item] = function() { 
     alert("thanks for your " + item); 
     }; 
    } 
    })();    
}