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

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

imqの回答

  • ベストアンサー
  • 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

関連するQ&A

  • javascriptのクロージャが理解できずに苦しんでいます。

    javascriptのクロージャが理解できずに苦しんでいます。 下記のようなコードをよく見るのですが、a()とfuncA()()が等価のようなのですが 実行するとa()の場合のみ変数の値が維持されます。 a()とfuncA()()の違いを理解したいと思っています。 どなたかどうぞよろしくお願い致します。 またクロージャのわかりやすい解説サイトなどご存知の方いらっしゃいましたら 合わせてよろしくお願い致します。 function funcA() { var i = 10; return function() { i++; alert(i); }; }; var a = funcA(); console.log(a() === funcA()())//true funcA()();//11 funcA()();//11 funcA()();//11 a();//11 a();//12 a();//13

  • クロージャ

    javascriptのクロージャについて。 クロージャにnewは必要ですか? コンストラクタであれば、newでオブジェクトを生成しますが、クロージャはどうでしょうか? クロージャ-------------------- function Person(n, a){ var name = n; var age = a; return { getName: function() { return name; }, setAge: function(i){ if( 0<= i ){ age = i; } }, getAge: function(){ return age; } } } var p = new Person('Hanako', 3); // new を付けなくても生成できる

  • javascript getelementsbytagnameについてです。

    var keisan=document.getElementsByTagName('input'); for(i=0;i<=keisan.length;i++){ if(keisan[i].getAttribute('value').match('Click')){ keisan[i].onclick=add(); } } function add() { var a = document.getElementById('number1').value; var b = document.getElementById('number2').value; var c = a - -b; alert(c); } 上のプログラムを入れると、"keisan[i]はnullです"といったエラーがでます。 kaisan.length=0になっているみたいです…。 xhtmlだと作動するのですが、htmlだと作動しません。 対応してないのでしょうか? 宜しくお願いいたします。

  • JavaScriptについて

    JavaScriptでボタンゲームを作っているのですが、ボタンを押して正解だった場合、色が変わり押せなくなるようにしたいのですが、うまくいきません。どうしたら良いか困っています。 原因として「順番が正しいかどうか判定する」ところじゃないかと思います。 <script type="text/javascript"> //初期処理 var suji = "(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)(12)(13)(14)(15)"; var pushed = ""; // 押されたボタン管理 var startTime; // ゲーム開始時間を管理 var labelArray = suji.split(""); // 数字を一文字ずつ分割 $("startButton").onclick = start; nextGame(); // スタートボタンを表示する // 開始準備 function nextGame() { $("buttons").innerHTML = ""; $("startButton").style.visibility = "visible"; } // ゲーム開始 function start() { $("startButton").style.visibility = "hidden"; // 配列に数字を代入して順番をシャッフル arrayShuffle(labelArray); // ボタンを作る for (var i = 0; i < labelArray.length; i++) { var b = document.createElement("button"); b.innerHTML = labelArray[i]; b.onclick = button_clickHandler; $("buttons").appendChild(b); } pushed = 0; startTime = (new Date()).getTime(); } // ボタンが押された時の処理 function button_clickHandler(e) { var ch = e.target.innerHTML; // 押されたボタンの文字 // 順番が正しいかどうか判定する if (suji.substr(pushed, 1) != ch) { alert("違います。次は、" + suji.substr(pushed,1)); } else { $("buttons").innerHTML=""; arrayShuffle(labelArray) for(var i = 0; i < labelArray.length; i++) { var b = document.createElement("button"); b.innerHTML = labelArray[i]; b.onclick = button_clickHandler; $("buttons").appendChild(b); } e.target.disabled = true; e.target.style.backgroundColor = "#909090"; pushed++; } if (pushed == labelArray.length) { var now = new Date().getTime(); var tm = Math.floor((now - startTime) / 1000); var min = Math.floor(tm % 3600 / 60); var sec = tm % 60; alert("おめでとうございます。\n"+ min + "分" + sec +"秒でクリアです!"); nextGame(); } } // 配列をシャッフルする function arrayShuffle(bs) { for (var i = 0; i < bs.length; i++) { var r = Math.floor(Math.random()*bs.length); var tmp = bs[i]; bs[i] = bs[r]; bs[r] = tmp; } } function $(id) { return document.getElementById(id); } </script>

  • JavaScript

    下記のプログラム(ボタン早押しゲーム)に以下のようなプログラムを入れたいのですが、どうすれば良いでしょうか? ・正しい順番にボタンが押されていれば毎回シャッフル(押されたボタンが色が変わり押せなくする。) 間違いならアラートで違うとメッセージを出す。 <script type="text/javascript"> // 初期化処理 var suji = "(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)(12)(13)(14)(15)(16)"; var pushed = ""; // 押されたボタン管理 var startTime; // ゲーム開始時間を管理 var labelArray = suji.split(""); // 数字を一文字ずつ分割 $("startButton").onclick = start; nextGame(); // スタートボタンを表示する // 開始準備 function nextGame() { $("buttons").innerHTML = ""; $("startButton").style.visibility = "visible"; } // ゲーム開始 function start() { $("startButton").style.visibility = "hidden"; // 配列に数字を代入して順番をシャッフル arrayShuffle(labelArray); // ボタンを作る for (var i = 0; i < labelArray.length; i++) { var b = document.createElement("button"); b.innerHTML = labelArray[i]; b.onclick = button_clickHandler; $("buttons").appendChild(b); } startTime = (new Date()).getTime(); } // ボタンが押された時の処理 function button_clickHandler(e) { var ch = e.target.innerHTML; // 押されたボタンの文字 var tmp = pushed + ch; // 順番が正しいかどうか判定する if (suji.substr(0, tmp.length) != tmp) { alert("違います。次は、" + suji.substr(pushed.length,1)); return; } e.target.disabled = true; e.target.style.backgroundColor = "#202020"; pushed = tmp; if (pushed == suji) { var now = new Date().getTime(); var tm = Math.floor((now - startTime) / 1000); alert("おめでとうございます。\n" + tm + "秒でクリア"); nextGame(); } } // 配列をシャッフルする function arrayShuffle(bs) { for (var i = 0; i < bs.length; i++) { var r = Math.floor(Math.random()*bs.length); var tmp = bs[i]; bs[i] = bs[r]; bs[r] = tmp; } } function $(id) { return document.getElementById(id); } </script>

  • JavaScriptのthisの挙動について

    JavaScriptで次のCodeのようなコードを書いて実行したところ、Outputのようになります。 原因は、thisが保持できていなかったからです。 ※先頭に#が付いているのが問題の箇所です。 Code: Array.prototype.rs = function() // rs = random sort { var ret = { list: new Array(), length: new Number() }; # var obj = { # list: this # }; var tmp = { index: new Number(), length: obj.list.length }; while((ret.length = ret.list.length) < tmp.length) { tmp.index = Math.floor(Math.random() * (tmp.length - ret.length)); ret.list[ret.length] = obj.list[tmp.index]; obj.list.splice(tmp.index, 1); } return ret.list; } var list = new Array(1,2,3,4,5,6,7,8,9); alert(list.rs()); alert(list.rs()); Output: アラートウィンドウで 2,4,6,9,3,5,1,8,7 (一例) アラートウィンドウで 出力無し 要するに、thisをobj.listに入れて、thisには触っていないのに、obj.listと同期してthisが消えているのです。 Code中で先頭に#を付けた部分を次のように変更すると期待通りに動作しましたが、腑に落ちません。 # var obj = { # num: this.join('') # }; # obj.list = obj.num.split(''); もっと簡潔な書き方や、迅速に動く書き方があればご教授頂きたいです。

  • 【DOM】HTMLのタグに対してはElementインターフェースが使えない?

    HTMLの「document」はXMLDocumentと完全に見立ててDOMを利用できないのでしょうか? <html>   <style>     .foo{       background: #999999;     }   </style>   <body>     <input class="foo" type="text" value="NNNN"/>   </body>   <script language=JavaScript type=text/javascript>   function hoge(){     var Nodes;     Nodes = document.getElementsByTagName("input");     alert(Nodes.item(0).nodeName)     alert(Nodes.item(0).getAttributeNode("class"))     alert(Nodes.item(0).hasAttributeNode("class"))   }   hoge();   </script> </html> 上記のようなコードを書いてもアラートに「foo」と表示されません。 また、hasAttributeNodeにおいては全く反応がありません。 DOMのElementインターフェースが使えないとすれば、 JavascriptからclassやonClickのイベントハンドラなど、 属性を動的に変更するにはどうすればいいでしょうか? 制限事項としてid属性やname属性は使用できません。 IE6での使用です。 以上、よろしくお願いします。

  • Javascriptで二次元配列で高次元の配列サイズを取得する方法を教えてください。

    Javascriptで二次元配列で高次元の配列サイズを取得する方法を教えてください。 var data = [ [1,2,3], [4,5,6], [7,8,9] ]; for (var i = 0; i < data.length; i++){ for (var j = 0; j < data[i].length; j++){ <--- ここで lengthのオブジェクトがNullというエラーになります。 alert(data[i][j]); } } よろしくお願いいたします。

  • JavaScriptで関数設定時に引数を指定したい

    状況を説明します ・複数のthにoncklickイベントで同じ関数を呼びたい ・th要素のタグにonclick属性を書くのは同じ記述をたくさん書くことになるのでやりたくない ・JavaScriptでonclick属性に関数を設定したい ・th要素自身を引数としたい ※WindowsXPのIE8で動けばOKです。 (0)ベタ書きするとこんな感じになります。これなら動くことを確認しています。 # <th onclick="func1(this)">… # <th onclick="func1(this)">… # <th onclick="func1(this)">… # <th onclick="func1(this)">… # # function func1(th) { #   … # } (1)引数がなければこんな感じになると思います # var ths = $("head").childNodes; # for (var i = 0; i < ths.length; i++) { #   ths[i].onclick = func1; # } (2)無名関数ならこんな感じになると思います # var ths = $("head").childNodes; # for (var i = 0; i < ths.length; i++) { #   ths[i].onclick = function() { #     … #   } # } しかしこの2つの書き方「(1)(2)」とも、引数を入れようとしたところ どうすればいいかわかりませんでした。 上記の状況を踏まえ… 質問は以下です ・(1)のような書き方で、引数アリの関数を設定する方法 ・(2)のような書き方で、引数アリの関数を無名関数で設定する方法 ・それ以外の代替方法 これを教えてください。 そもそもJavaScriptではできないのであればその旨を教えてください。 よろしくお願いします。

  • Javascriptで引数の参照渡しか戻り値を複数取得したい

    Javascriptで引数を参照渡しを行いたいのですが空で返ってきます。 どうすればよいのでしょうか? 参照渡しの引数がうまくいかない場合は戻り値を2つ返す方法と受け取る記述の仕方など知りたいです。 function test(indat, outdat, retval){ outdat = []; for (var i=0; i<indat.length; i++){ outdat[i] = indat[i]; } retval = 123; } var indat = new Array(); var outdat= new Array(); var retval = ""; indat[0] = 'A'; indat[1] = 'B'; indat[2] = 'C'; test(indat, outdat, retval); for (var i=0; i<outdat.length; i++){ alert(outdat[i]); } alert('retval=[' + retval + ']');