人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

javascriptに関する質問です。

a=1;
function hoge(){
var a=2;
setTimeout("alert(a)",1000);
setTimeout(function(){alert(a)},2000);
}
hoge();

上の結果が「1」「2」となるのは何故なんでしょうか?

●質問者: Lhankor_Mhy
●カテゴリ:ウェブ制作
✍キーワード:hoge JavaScript
○ 状態 :終了
└ 回答数 : 7/7件

▽最新の回答へ

1 ● jippu
●25ポイント

まず、関数の外と中で定義している変数aが別のものになります。(関数内でvarで宣言されてるため)

最初のalertは、グローバルとして動くalertなので、関数の外のaを参照します。

二つめのalertではhoge関数内で働くため、関数内のaを参照します。

ということではないでしょうか。

ちなみに、試されてるかもしれませんが、関数内でvarを取ると、グローバルのaを書き換えるので、どちらも2になります。

◎質問者からの返答

有難うございます。

最初のalertと2つ目のalertが何故スコープが変わるのか知りたいです。引き続きよろしくお願いします。


setTimeout(alert(a),2000);

こちらでも、エラーが出ているのですが「2」になるのです。


2 ● jippu
●25ポイント

イメージ的にはこういう感じではないでしょうか?

a=1;

function kansu(s){

alert(s);

}

function hoge(){

var b=2;

setTimeout("kansu(a)",1000);

setTimeout(function(){alert(b)},2000);

}

hoge();

◎質問者からの返答

なるほど。


3 ● suenaga3
●25ポイント

1つ目の関数はダブルクォートで囲まれているので、実行時にaの変数を参照しますが、

2つ目は、宣言時にaの値を渡しています。

1つ目の関数も、

setTimeout("alert(" + a + ")",1000);

とすれば、「2」が表示されるかと思います。

◎質問者からの返答

でも、


eval("alert(a)");


は「2」で返ってくるんです。

これは、もう、体系的に理解しようというのが間違っていて、setTimeoutの仕様として考えるしかないのでしょうか? 何故にそんな混乱しそうな仕様にしたのでしょうか。


4 ● susie-t
●150ポイント

結論から言うと、仕様として考えるしかないと思います。

コードが文字列で指定されているか否かでスコープが決まるわけではなく、それはあくまで各関数の仕様によります。

また、

http://www2u.biglobe.ne.jp/~oz-07ams/prog/js-notes/setTimeout.ht...

にも書かれている通り、IEとFirefoxとでもその動作は微妙に違います。

当初、文字列指定のみで関数指定はできなかったようですから、その際スコープをグローバルにしたのでしょう。(あくまで想像ですが。) クロージャのレキシカルスコープは分かりにくい部分もありますし・・・。

ただ、確かに混乱しますね。個人的には、文字列指定は使わずに関数指定だけを使っています。

◎質問者からの返答

有難うございます。


だめだ。リンク先を見ている段階で混乱してきました。必要のないときは変数で渡さないようにしようと思いました。


5 ● quintia
●50ポイント
a=1;
function hoge(){
 var a=2;
 setTimeout("alert(a)",1000);
 setTimeout(function(){alert(a)},2000);
}
hoge();

は、

a=1;
function hoge(){
 var a=2;
 function huga() {
 alert(a);
 }
 setTimeout("alert(a)",1000);
 setTimeout(huga,2000);
}
hoge();

と同じです。(正確には2つの setTimeout の間に fuga() の宣言を書くべきですが無視)


挙動を"感覚"できるように、

a=1;
function hoge(){
 var a=2;
 function huga() {
 a = a + 1;
 alert(a);
 }
 setTimeout("alert(a)",1000); 
 setTimeout(huga,2000);
 setTimeout(huga,3000);
}
hoge();

としてみましょう。

結果は 1,3,4 と出てきます。

hoge の中で var a で確保された変数が、fuga の実行ごとに1増えています。


もう setTimeout("alert(a)",1000); は無視して話をしますよ。

a=1;
function hoge(){
 var a=2;
 function huga() {
 a = a + 1;
 alert(a);
 }
 setTimeout(huga,2000);
 setTimeout(huga,3000);
}
setTimeout(hoge, 1000);
setTimeout(hoge, 10000);

とすると 3,4 と出て、ちょっと(7秒ほど)してまた 3,4 とでてきます。

  1. "hogeの中のa"という変数を確保 (実行されたhogeに束縛されたa とでも言うべき?)
  2. "hogeの中のa"に2を代入
  3. hugaの実行(1回目のhogeの1回目)→"1回目のhogeに束縛されたa"が3になり、"3"が表示される
  4. hugaの実行(1回目のhogeの2回目)→"1回目のhogeに束縛されたa"が4になり、"4"が表示される
  5. "hogeの中のa"という変数を確保
  6. "hogeの中のa"に2を代入
  7. hugaの実行(2回目のhogeの1回目)→"1回目のhogeに束縛されたa"が3になり、"3"が表示される
  8. hugaの実行(2回目のhogeの2回目)→"1回目のhogeに束縛されたa"が4になり、"4"が表示される

の順に実行されてます。


hogeの実行の度に(グローバルじゃない)変数aの領域が確保され、それがhogeに束縛されている、と考えればいいでしょう。

つまり、"1回目のhogeに束縛されたa"と"2回目のhogeに束縛されたa"は別であるという概念で捉えてみて、それが正しいかどうかを確認するためのソースを書いてみます。

b=1;
function hoge(){
 var a=b;
 function huga() {
 a = a + 1;
 alert(a);
 }
 setTimeout("b=b+10",1000); 
 setTimeout(huga,2000);
 setTimeout(huga,10000); //※
}
setTimeout(hoge, 1000);
setTimeout(hoge, 5000);
setTimeout("alert(b)", 20000);

※の行が遅延して実行される様に時間設定しています。

こういう風に実行されるだと考えられます。

  1. グローバル変数bの確保と1の代入
  2. hogeの実行(1回目)
  3. "1回目のhogeに束縛されたa"の確保と、グローバル変数bの値1の代入
  4. b=b+10の実行によりグローバル変数bの値が11になる
  5. hugaの実行(1回目のhogeの1回目)→"1回目のhogeに束縛されたa"が2になり、"2"が表示される
  6. hogeの実行(2回目)
  7. "2回目のhogeに束縛されたa"の確保と、グローバル変数bの値11の代入
  8. b=b+10の実行によりグローバル変数bの値が21になる
  9. hugaの実行(2回目のhogeの1回目)→"2回目のhogeに束縛されたa"が12になり、"12"が表示される
  10. hugaの実行(1回目のhogeの2回目)→"1回目のhogeに束縛されたa"が3になり、"3"が表示される
  11. hugaの実行(2回目のhogeの2回目)→"2回目のhogeに束縛されたa"が13になり、"13"が表示される
  12. グローバル変数bの値、"21"が表示される

実行すると確かに 2,12,3,13,21 の順に表示されます。


解答、解説じゃなくてすみません。

質問が興味深かったので色々と実験してみた結果でした。

◎質問者からの返答

えっと、難しいです。これは何かのイジメですか(w


ところで、最後のなんですが。

b=1;

function hoge(){

var a=b;

function huga() {

a = a + 1;

alert(a);

}

setTimeout("b=b+10",1000);

setTimeout(huga,10000); //※

setTimeout(huga,2000);

}

setTimeout(hoge, 5000);

setTimeout(hoge, 1000);

setTimeout("alert(b)", 20000)

これでも実行結果同じなんですね。これは危険が危ない。


1-5件表示/7件
4.前の5件|次5件6.
関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ