• ベストアンサー

forの中でsetTimeoutする時のスコープ

下記のようなソースで上手くsetTimeoutが効きません。 for(var i = 0; i < 5; i++){ target = obj[i]; setTimeout(function (){ target.css('background-image', 'fuga'); }, 100 * i); } デバッグで見てみると、どうも変数targetが空になっているようのですが、for文の中でsetTimeoutは不可なのでしょうか? jqueryの$.eachを使うとうまくいったのですが、、、

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

  • ベストアンサー
  • b0a0a
  • ベストアンサー率49% (156/313)
回答No.2

関数内のtargetは実行時に外のtargetを参照します つまりそれまでにtargetが変わってしまっていた場合思った通りに実行されません このコード以外にtargetを弄る部分がないとしても、 5回呼ばれる関数内でのtargetは5回ともobj[4]を指します なぜなら実行時にはtargetはobj[4]となっているからです つまり結論をいうとその書き方ではダメです 治すパターンはおそらく5つくらいはありますが、 setTimeoutの場合第三以降の引数を使うといいでしょう for(var i = 0; i < 5; i++){ target = obj[i]; setTimeout(function (target){ target.css('background-image', 'fuga'); }, 100 * i, target); } こうすれば毎ループ毎に期待通りのtargetが関数に渡されるようセットされ、 関数内のtargetはその渡されるtargetの方を参照するのでうまく行きます

その他の回答 (1)

noname#247307
noname#247307
回答No.1

setTimeoutの中にある無名関数は、このfor文が実行されている関数とは別のものですよね? この関数内にある関数ではないわけですね。なぜって、setTimeoutが呼ばれたらその関数が実行されるわけではなくて、指定した時間が経過後に呼び出されるコールバックなわけですから。 ということは、この無名関数が呼び出されたとき、既にforのある関数は実行が終了していて、その中で宣言された変数も全て開放されていると考えないといけないでしょう。 従って、一番わかりやすい解決法は、obj配列をグローバル変数として保管しておき、無名関数内ではそのグローバル変数を参照して処理する、というものでしょう。jQueryがうまく動いたのも、あれはjQueryオブジェクトというグローバルオブジェクト内にすべての情報を保管するように設計されているからじゃないでしょうか。 あるいは、引数としてオブジェクトを渡すという手もあります。ただしこの場合、ちょっと注意が必要です。 setTimeout(function(){ func(target); } function func(target){ …… } こんな感じで、別途setTimeout時に呼び出される処理を関数にまとめておき、無名関数内からそれを引数付きで呼び出す、といった形にしないとうまくいかないでしょう。

関連するQ&A

  • jQueryのforとeachの変数参照の違い

    jQueryを学習中の者です。 現在、パララックス効果のサンプルコードを参考にしているのですが、理解できずに困っています。 その内容は各ブロック要素をeachでループさせ、ループの中でウインドウのスクロールイベントを登録しコールバック関数で細かい設定をしていくというものです。 理解できないというのは、以前 javasctiptでのfor文による要素へのイベント登録で「イベントでも渡す関数は参照のみです。新たに関数を自動で作成してくれるような事は決してありません。」と説明が有り、コールバック関数内に変数を使うとイベント発生時に変数を参照した時、ループの最後で格納した値になるので、この事は理解し注意もするようにしていました。 しかし、今回のサンプルコードではforとeachの違いはあるけれど、コールバック関数に変数を使っているのに、その変数が別々の値を持っています。 最初はjQueryとjavascriptの挙動の違いかなと思い、以前のfor文のコードを下の様にjQueryで書き替えても結果は一緒でした。 取り留めの無い文章になってしまいましたが、どうして下の2つコードが違う結果になるのかを解り易く説明していただけませんでしょうか。 <table border="1"> <tr><td></td><td></td>...</tr> ... </table> <script> (1)//これだと、駄目…どのtdのイベントでも最後のtdが反応 $(function(){ for(var i =0 ,len=$('td').length;i < len; i++){   var td=$('td').eq(i);   td.mouseover(function(){ td.css('background-color','red');});   td.mouseout(function(){ td.css('background-color','');});  } }); (2)//これだとOK…ちゃんと各tdが反応する。 $(function(){  $('td').each(function(index,elem){   var td=$(elem);    td.mouseover(function(){ td.css('background-color','red');});    td.mouseout(function(){ td.css('background-color','');});  }); }); </script> *今回の質問はどう対処したら良いのかという類ではありません。 両方とも変数 td にjqueryオブジェクトを格納して、同じ形式でイベント登録しているのに違う結果になるという事が壁に成ってます。 ネットでいくら調べても構文の説明やサンプルコードは溢れていますが、この様な事例に触れた物が皆無です。 forとeachの違いなんて基本的なことで恥ずかしいのですが、お願いします。

  • Javascriptのスコープについて。

    私は何か大きな勘違いをしているでしょうか? for(var i=0; i<10; i++){ for(var i=0; i<10; i++){ alert(i); } } 単純なこのサンプルで、ループは総計100回回るはずだと思うのですが、 外側ループのローカル変数であるiが、なぜか内側ループのローカル変数iと同一視され、 結果10回しか回りません。 どこがおかしいでしょうか。 比較対象として、以下を実行しました。 var i=3; (function(){ var i = 2; alert(i); })(); alert(i); 結果は2, 3となりました。 スコープは機能しています。 前者はfor文だからおかしくなったのでしょうか? ・・・while文で書き下すと、あ、for文の()中で宣言するカウンタ変数というのは、該当for文のスコープの外に出ちゃっているんですね・・・。 つまり、for(var i・・・)と宣言したカウンタ変数のスコープは、for(){}のスコープではなく、その一個外に所属すると。。 こういう解釈でよいのでしょうか?よろしくお願い致します。m(_ _)m var i=0; while(i<10){ var i=0; while(i<10){ alert(i); i++; } i++; }

  • JavaScriptのsetTimeoutについて

    setTimeoutのタイマー処理の仕様を調べています。 var func = function () { alert(1); }; setTimeout(func, 1000); alert(2); このコードを実行した場合、alert(2)→alert(1)の順で処理されるのは当然ですが、 alert(2)を開いたまま1秒以上待ち、そこでOKボタンを押すとどうなるか、という問題です。 Firefoxの実装については下記ページで分かりました。 http://takoyakim.tumblr.com/post/10875885/firefox-settimeout 先ほどのコードの1000ミリ秒の経過処理は、タイマースレッドという専用スレッドで扱うため、 alert(2)で1000ミリ秒以上止めた後にOKボタンを押すと、即座にalert(1)が開きます。 しかしIEの場合はそうではなく、alert(2)を閉じてから約1000ミリ秒後にalert(1)が開きました。 alert(2)を開いたままどれだけ待機しても変わりません。 ChromeやSafariもIEと同じようです。 ですがこの結果は、次のコードの実行結果と矛盾してしまいました。 var heavyFunc = function () { for(var i = 0; i < 100000; i++) new Date(); } var startTime = +new Date(); var callCount = 0; var testFunc = function (x) { heavyFunc(); // (1) if (++callCount < 5) setTimeout(testFunc, 100); else alert(+new Date() - startTime); //heavyFunc(); // (2) }; testFunc(); heavyFuncという重い処理を、setTimeoutの前後のどちらに置くかという実験コードです。 setTimeoutのタイマー処理がFirefoxのように別スレッドで実行されているのであれば、 先にsetTimeoutを呼び出してからheavyFuncを実行した方が速く処理が完了するだろう、という想定です。 そして結果は、FirefoxだけでなくIEとChromeでも先にsetTimeoutを呼んだ方が速い、となりました。 結局どのブラウザも専用のタイマースレッドを実装しており、 alert関数が特殊(タイマースレッドもブロックする)なだけ、ということなのでしょうか? それとも私が何か見落としているのでしょうか。

  • (function(){})()の意味

    (function(){})() の意味がよくわからずに困っています。 下記の2タイプではどう意味が変わってくるのでしょうか? (1)var fuga = function(){}; (2)var fuga = (function(){})(); 下記のコードで実験してみたところ、 --------------------- var fuga = function(){ this.obj = 'value'; }; var fuga = (function(){ return { obj = 'value'; }; })(); --------------------- (1)の場合は、newしないとfugaオブジェクトのメンバを使用できない、 (2)の場合は、newしなくてもfugaオブジェクトのメンバを使用できるようなのですが、 (2)で(function(){})を取り除いて出てくる()はnewのエイリアスだったりするのでしょうか? 

  • setTimeoutをループさせDOMを処理したい

    「setTimeout」「for文」「jQuery」を利用して、1秒ごとに、 <div class="hoge1">、<div class="hoge2">、<div class="hoge3">へ対して、同じ処理をしたいです ■処理内容イメージ ・ループカウントの変数iを渡して、それぞれのdiv内で、1、2、3と表示 ■質問 「setTimeout」を1秒ごとに、指定DOMへ対して、ループさせる方法を教えてください ※ループできるなら、「for文」じゃなくても良いです

  • setTimeout の動作不良?

    setTimeout の中で引用する関数が引用するカッコの中に 引用符で文字列を入れると正常に作動しますが 変数名を入れると、動作が停止してしまうようです。 Win 7 pro 上で、Firefox 、 IE11 の両方で試しましたが どちらも動きませんでした。 おそらく、setTimeout のバグではないかと個人的に考えていますが どのようにして、この問題を解決可能かを 教えて下さい。 <script> function TestA() { setTimeout( "alert('Hello')", 2000) ; } function TestQuote() { var stringQ = 'Hello' setTimeout( "alert(stringQ)", 2000) ; } function TestNoQuote() { var stringQ = 'Hello' setTimeout( alert(stringQ), 2000) ; } </script> </head> <body> <button onclick="TestA()" > Timer 1 </button> <button onclick="TestQuote()" > Timer 2 </button> <button onclick="TestNoQuote()" > Timer 3 </button>

  • forの中にいれたcreateTextの使い方

    はじめまして、 内容をまとめて書いてあるテキストがあり、これを変数に入れて分割したものを画面に表示させたいのですが、表示するところがうまくいきません。 createTextの書き方がおかしいと思うのですがどこを書き換えればいいのかわかりません。 すいませんがどなたかお教え願えないでしょうか。 var text1=new LoadVars(); text1.load("test.txt") text1.onLoad=function(){   var test_array:Array=text1.split(",");   for(var i=0;i<test_array.length;i++){   this.createTextField("c"+[i],this.getNextHighestDepth(),50,20+i*20,200, 20); this.c[i].text =test_array[i]; } 多分thisのあたりがおかしいと思っているのですが、どう書けばいいのかわかっていません。 すいませんがどなたかお願いします。

  • javascriptのforループ中の変数について質問です。

    javascriptのforループ中の変数について質問です。 下記のようなコードを書きました。 function test(){ for (i = 0;i < 3;i++){ var msg = "msg"+i; setTimeout(function(){ alert(msg); },1000 * i); } } これを実行すると、1秒間隔で順番に"msg2"→"msg2"→"msg2"と表示されます。 しかし、期待する動作は1秒間隔で順番に"msg0"→"msg1"→"msg2"なのです。 この動作を実現するために、どのようにスクリプトを修正すればよいか、ご教授いただければ幸いです。

  • useless setTimeout cal 

    すみません。教えて下さい。 下のコードを書いて、動きはするんですが、実行後に 「useless setTimeout cal」というエラーが出てしまいます。 エラーを回避したいのですが、どうすればいいのでしょうか。 IE6/IE8/firefox3.6 などで試しました *********************************** <html> <head> <script type = 'text/javascript'> function item(){ var i = 0; write(); function write(){ document.write(i+"<br>"); i ++; if(i<10){setTimeout(write(),100);} } } </script> </head> <body> <script type = 'text/javascript'>item();</script> </body> <html> ***********************************

  • 分からないプログラムの流れ

    外部ファイル function changeCSS(sURL) { var obj = document.getElementsByTagName("link"); for (var i=0, cnt=0; i<obj.length; i++) { if (obj[i].type == "text/css") obj[i].href = sURL[cnt++]; } } 本体 <a href="#" onClick="changeCSS(['main.css','sb.css'])">1</a> <a href="#" onClick="changeCSS(['main.css','sb2.css'])">2</a> <a href="#" onClick="changeCSS(['main2.css','sb.css'])">3</a> cntがいらない様に思えるのですが消すと動作しなくなってしまいます どのように使われているのかプログラムの流れを教えてください