• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:JavaScriptのクロージャの挙動の違い)

JavaScriptのクロージャの挙動の違い

このQ&Aのポイント
  • JavaScriptのクロージャには異なる挙動があります
  • イベントハンドラのコピーではなく、関数の引数を利用することで問題を解決できます
  • 正しいクロージャの使い方を理解することが重要です

質問者が選んだベストアンサー

  • ベストアンサー
  • imq
  • ベストアンサー率72% (16/22)
回答No.5

#3の返答です。 >共用 これは言葉通りの意味です。 var add_handler = function(nodes) {  var i; // ←共用される変数i  for(i = 0; i < nodes.length; i += 1) {   nodes[i].onclick = function(e) {    alert(i); // ←このiはクリックした時点のi   };  } }; では nodes[0].onclick = function(e) { alert(i); }; nodes[1].onclick = function(e) { alert(i); }; … nodes[n].onclick = function(e) { alert(i); }; と、全てのノードのonclickイベントハンドラで同じ変数iが使われているので共用と書きました。 共用されているので、時系列で考えてクリックした時点のiは既にforループを脱している(add_handler関数も脱している)ので、nodes.lengthの値になります。 クロージャの特性上こんなことが言えると思います。 ・各ノードのonclickはadd_handlerのクロージャへの参照です ・そのクロージャで、上位スコープ(add_handler)の変数iを使っています ・add_handlerの実行すると、最終的に変数iはnodes.lengthの値になります ・クロージャはonclickの参照先とされたため、add_handler実行後も残ります。 ・そのクロージャで変数iが使われているため、add_handlerの実行後も変数iは生き残り、値も保持されます

cevid_cpp
質問者

お礼

おおー! onclick=から先のfunctionの部分は、クリックされてからじゃないと読み込まれない。 普通のコードとは違う所で実行される認識。 このことを頭に入れたら完全に解決できました! だからイベントハンドラの時は気をつけないといけないのですね。 このスッキリした気分、最高です。 ありがとうございましたmm

その他の回答 (4)

回答No.4

#1です 例の5番 var f = function(n){ return function() { alert(n); }; }(5); f(); //←これは引数がなくても5をアラーとするよね あなたが提示した nodes[i].onclick=function(i){ return function(e){ alert(i); }; }(i); を、1ぎょうにする。 nodes[i].onclick=function(i){return function(e){alert(i);};}(i); もし i=5 のとし、いわゆるくろーじゃのへんすうを i から n にすると nodes[5].onclick=function(n){return function(e){alert(n);};}(5); 最初の例5 var f = function(n){ return function() { alert(n); }; }(5); nodes[5].onclick = f; で、同じ。

cevid_cpp
質問者

お礼

改行を入れるとどこに;を入れるべきなのか混乱するので、 確かに1行で書くとそういうのはわかりやすいですね。 そして問題の本質もなんとか理解することができました。 ご協力ありがとうございました。

  • imq
  • ベストアンサー率72% (16/22)
回答No.3

理由は恐らく考えている通りだと思います。 各ノードのイベントハンドラは上位スコープにある変数iを共用しているので、ノードをクリックしたときにはすっかりforループを抜けていて、iはnodes.lengthの状態でアラートされます。 正しい方はfunctionを設けてスコープを一段下げることで、変数iの共用を避けています。 つまり、アラートしているiは上位スコープの変数iではなく、引数として与えられたiです。 for内のfunctionは、ループで実行するたびに動的に生成されるので、i=0の時とi=1の時は別のfunctionとなり、引数も生成されたときのものが保持されることになります。 変数名と引数が同じiだと紛らわしいので、 var add_handler = function(nodes){  var i;  for(i = 0; i < nodes.length; i += 1) {   nodes[i].onclick = function(j) {    return function(e) {     alert(j);    };   }(i);  } }; とした方が分りやすいでしょうか。 ちなみに最近では上記のようにクロージャを返すんじゃなくて、forループ内をfunctionでラップしてしまうことも多いです。 var add_handler=function(nodes){  var i;  for(i = 0;i < nodes.length; i += 1) {   function(j) {    nodes[j].onclick = function(e) {     alert(j);    };   }(i);  } }; JavaScriptではよく使う手法ですね。

cevid_cpp
質問者

お礼

ありがとうございます! 私は「変数を共用している」ということの意味が良く分かっていません。 本にも「実際の変数」みたいなことが書かれていて、何かそこが曖昧な感じがしています。

  • fujillin
  • ベストアンサー率61% (1594/2576)
回答No.2
cevid_cpp
質問者

お礼

ありがとうございます! しっかりと読もうと思います。 クロージャの部分を読んでみたのですが、そこのクロージャは個人的には理解できていると思っています。 しかし、このイベントハンドラが来た場合にしっくりきません。。

回答No.1

どこまでわかる? //_ alert(1); //_ var f = function(n) { alert(n); }; f(2); //_ (function(n) { alert(n); })(3); //____ var f = (function(n) { alert(n); })(4); // f = undefined //____ var f = function(n){ return function() { alert(n); }; }(5); // typeof f == 'function' f(); //____ (function(n){ return function() { alert(n); }; })(6)();

cevid_cpp
質問者

お礼

4つ目はalert(4)した戻り値がないからundefinedなのでしょうか。 5,6つ目は関数を返してそれを実行しているのかな、という認識が持てる程度です。 自分でこのようなコードは書けないと思います。

関連するQ&A