• ベストアンサー

処理のしくみがわかりません・・・

以下のスクリプトはfor文による繰り返し処理の例です。 <script type="text/javascript"> <!-- var a="あ"; var b=new Array("い","う","え","お"); function FUNC1(){ for(i=0;i<b.length;i++){ a=a+b[i]; } document.write(a); } function FUNC2(){ for(i=0;i<b.length;i++){ document.write(a=a+b[i]); } } //--> </script> FUNC1の関数を実行すると、「あいうえお」、 FUNC2の関数を実行すると、「あいあいうあいうえあいうえお」 と表示されるのは理解できます。 それで試しにこのスクリプトの最後に、 FUNC1()+FUNC2(); を追加したところ、 「あいうえおあいあいうあいうえあいうえお」 と表示されると思いきや、 「あいうえおあいうえおいあいうえおいうあいうえおいうえあいうえおいうえお」 と表示されました。 どうもFUNC2を足す時、グローバル変数 a が "あ" ではなく、 "あいうえお" と代入されて実行されてるみたいです。 そして、FUNC1、FUNC2を実行すると、それぞれ 「あいうえおいうえおいうえお」 「あいうえおいうえおいあいうえおいうえおいうあいうえおいうえおいうえあいうえおいうえおいうえお」 と、理解不能の文字の並びになってしまいました。 なぜ FUNC1()+FUNC2(); を追加したらそれぞれの関数の実行値が変わってしまったのでしょうか? その処理の仕組みをご教授お願いいたします<(_ _)>

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

  • ベストアンサー
noname#199778
noname#199778
回答No.3

再び失礼します。 補足読みました。 おそらく、補足の内容の > しかし、それを例えばonClickイベントハンドラを使って それぞれFUNC1()、FUNC2()を実行した場合、 FUNC2()の実行結果は、当然 「あいあいうあいうえあいうえお」 と表示されますよね。 この場合、FUNC1()の処理後もグローバル変数 a は "あ" のままだということになります。 でもそうなると、やはりつじつまが合わなくなるんです。 (例えば、カウンターを使って0と1を切り替えて処理を繰り返すことができなくなりますよね) > この部分は、誤解があると思います。 実際にこのスクリプトを走らせてみるとわかると思いますが、上のスクリプトではdocument.write()で内容を書き出すので、onClickで実行されるように整えると、それまでのページ内容を破棄してしまいます。 そうすると、そのときのスクリプトなどの内容もすべてリセットされてしまうので、これではグローバル変数の扱いを確認することはできません。 これを実行した後に表示されるページの、HTMLソースを表示してみてください。 もしそこで実行結果の文字列だけが表示されているのであれば、そのソースがそこで参照されているソースということになります。 元のページに戻れば(バックボタンで戻ってますよね?)、再びソースを読み込みなおして、スクリプトの変数の定義なども初期状態に戻ってしまうでしょう。 こちらの動作の確認の際には、var a="あ";の下に、alert(a)と入れておくとよいでしょう。 ページロード時に初期状態の変数aが表示されます。 onClickで関数を呼び出す形にして、その内容によって変数aの扱いがどのようになっているのかを確認したいのであれば、スクリプトを以下のようにして、それをイベントハンドラから呼び出してみてください。 <script type="text/javascript"> <!-- var a="あ"; var b=new Array("い","う","え","お"); function FUNC1(){ for(i=0;i<b.length;i++){ a=a+b[i]; } alert(a); } function FUNC2(){ for(i=0;i<b.length;i++){ a=a+b[i]; } alert(a); } //--> </script> document.write()を外して、各関数の処理終了時に変数aの値をアラートダイアログで表示するようにしてあります。 これをonClickのイベントハンドラで呼び出し、変数aがどのように継続して扱われているかを確認してみるのが良いでしょう。 もしFUNC1()でもFUNC2()でも、いずれの関数を呼び出したときにもアラートダイアログの内容が 「あいうえお」 「あいうえおいうえお」 「あいうえおいうえおいうえお」 「あいうえおいうえおいうえおいうえお」 のように伸びていくようであれば、変数aがグローバル変数として処理されていることがわかると思います。 もしくは、#2の方が提示されたスクリプトを試されると良いと思います。 #2の方のスクリプトでは、それぞれの実行結果を確認できるので、間接的に変数aの値の推移を知ることが可能でしょう(回答に乗っかってしまって失礼しました)。 たぶん、ページロード後にdocument.write()で内容を書き出そうとすると、それまでの内容を破棄してしまうという点を、ページ内容が継承されていると誤解されているのではないかと思います。 それさえ把握できれば、疑問は晴れるのではないでしょうか。 再び失礼しました。

spnk55
質問者

お礼

まさにツボをついた回答ありがとうございます。<(_ _)> いろいろ試してみて、他ではグローバル変数の値が変更されるのに、 今回のようなdocument.writeメソッドを使った時には、 グローバル変数の値が変わらないので、???と思っていました。 FUNC1やFUNC2を実行した後、ページを元に戻ると、 再びページロードした際に、グローバル変数 a は、 a="あ" と定義しなおされるということですね。 leadさんとgimmickさんが提示していただいた例文に加えて、 サブウィンドウを開き、そこに document.write で a の値を書き出す方法も試して、すべての謎が氷解しました。 今回はどうもありがとうございました。 またよろしくお願いいたします<(_ _)>

その他の回答 (2)

  • gimmick
  • ベストアンサー率49% (134/270)
回答No.2

>しかし、それを例えばonClickイベントハンドラを使って >それぞれFUNC1()、FUNC2()を実行した場合、 >FUNC2()の実行結果は、当然 >「あいあいうあいうえあいうえお」 >と表示されますよね。 そのときのグローバル変数aの値に依存します。aが""だったらそうなります。 >この場合、FUNC1()の処理後もグローバル変数 a は "あ" のままだということになります。 そうはならないはずです。 >こうなると、変数 a はグローバル処理用とローカル処理用2つ存在しているようにも思えてきます。(汗) >もしくは、それぞれ別個に関数を実行する場合は、グローバル変数 a は、それぞれの関数用に >(今回の場合だと、FUNC1用とFUNC2用に) >存在しているということでしょうか? これも違います。 document.write()を使うと別ページに移動してしまってわかりにくいので、 こんなコードを書きました。これで試すとaの値が保持されているのがわかるかと思います。 ---------------------------------------------------------------------- <html> <head> <script language="JavaScript"><!-- var a="あ"; var b=new Array("い","う","え","お"); function FUNC1(){   for(i=0;i<b.length;i++){     a=a+b[i];   }   write(a); } function FUNC2(){   for(i=0;i<b.length;i++){     write(a=a+b[i]);   } } function write(str){   form1.a.value += str; } //--></script> </head> <body> <form name="form1"> <input type="button" value="FUNC1" onclick="a.value='';FUNC1()"> <input type="button" value="FUNC2" onclick="a.value='';FUNC2()"><br> <input type="text" name="a" size="100" readonly> <form> </body> </html>

spnk55
質問者

お礼

gimmickさんとleadさんの協力のもと、 サンプルスクリプトまで提示していただき、 おかげでなんとか理解することができました。 今回はどうもありがとうございました。 またよろしくお願いいたします<(_ _)>

noname#199778
noname#199778
回答No.1

処理の過程を順に追ってみてはいかがでしょう。 FUNC1()の処理では、グローバル変数a自体に配列bの内容を順次加えていくため、FUNC1()の処理が終了する際にはグローバル関数自体が既にa="あいうえお"になっているものと思われます。 そのループが終わったときに、document.write(a)で変数aを書き出すと、その内容の「あいうえお」が出力されますね。 ついで、変数aが持っている値「あいうえお」がグローバル変数として扱われれば、FUNC2()の処理時には「あいうえお」に対して、bの配列の項目を一つずつ足し合わせるように定義しているので、変数aには順次配列b内の文字が再び追加されます。 ただ、こちらの処理では、ループが回るたびに変数aを再定義しつつ表示するので、ループの過程が出力されてきます。 具体的には、こちらの出力結果を追えば、ループごとに 「(あいうえおい)+(あいうえおいう)+(あいうえおいうえ)+(あいうえおいうえお)」 となります。 で、これを見直してみると、FUNC1()+FUNC2()という処理では、FUNC1()の内容が処理された 「あいうえお」 と、FUNC2()の内容が処理された 「あいうえおいあいうえおいうあいうえおいうえあいうえおいうえお」 が平行して出力されるので、結果として 「あいうえおあいうえおいあいうえおいうあいうえおいうえあいうえおいうえお」 という結果になると思います。 また、FUNC1()+FUNC2()を処理した後では、この処理を終了した時点で変数aの持つ値は「あいうえおいうえお」になっています。 FUNC1()の終了時の変数aの値は、「あ」に配列bの要素を順次加えた 「あいうえお」 に、FUNC2()の終了時の変数aの値はFUNC1()の処理終了後の値に、更に配列bの要素を順次加えた 「あいうえおいうえお」 になっているはずです。 そこで、更にFUNC1()を呼び出せば、変数aは三度配列bの要素を順次追加され、FUNC1()のループ終了時の変数aは 「あいうえおいうえおいうえお」 と、「あ」+(「いうえお」×3回)という結果になります。 また、上のFUNC1()の再実行の代わりに、FUNC2()を実行すれば、今度は上の「あいうえおいうえお」に対して、順次配列bの要素を足して再定義された変数aを表示するので、ループするたびに 「あいうえおいうえおい」 「あいうえおいうえおいう」 「あいうえおいうえおいうえ」 「あいうえおいうえおいうえお」 を表示します。 最終的には、 「あいうえおいうえおいあいうえおいうえおいうあいうえおいうえおいうえあいうえおいうえおいうえお」 となるでしょう。 おそらく、ここでは関数内の変数がローカル変数になっていると捉えている誤解があって、予測しない結果になったのではないかと思います。 Javascriptでは、関数内での変数は、変数名からいきなり記述すると、基本的にグローバル変数として扱われます。 ローカル変数として定義するときには、関数の中で変数を定義するときに「var 変数=値」という形式をとる必要があるでしょう。 参考になれば…見当違いでしたら、ごめんなさい。 乱文失礼しました。

spnk55
質問者

補足

丁寧な回答ありがとうございます<(_ _)> アドバイスを参考に、 a=a+b[i]; の部分を a=a+b[i]+"●["+i+"回目]"+"<br>"; などに変えながらいろいろ試して、ようやく処理の流れを実感できました。 グローバル変数は、関数内でその値が変更された場合、グローバル変数自体の値が変わる・・・ というのは、上で記述している<script>~</script>の例だと、 スクリプトの最後に FUNC1(); FUNC2(); を記述した場合、FUNC1()処理後にグローバル変数 a が "あいうえお" に変更され、 FUNC2()の実行結果が 「あいうえおいあいうえおいうあいうえおいうえあいうえおいうえお」 となることでよくわかりますね。 しかし、それを例えばonClickイベントハンドラを使って それぞれFUNC1()、FUNC2()を実行した場合、 FUNC2()の実行結果は、当然 「あいあいうあいうえあいうえお」 と表示されますよね。 この場合、FUNC1()の処理後もグローバル変数 a は "あ" のままだということになります。 でもそうなると、やはりつじつまが合わなくなるんです。 (例えば、カウンターを使って0と1を切り替えて処理を繰り返すことができなくなりますよね) こうなると、変数 a はグローバル処理用とローカル処理用2つ存在しているようにも思えてきます。(汗) もしくは、それぞれ別個に関数を実行する場合は、グローバル変数 a は、それぞれの関数用に (今回の場合だと、FUNC1用とFUNC2用に) 存在しているということでしょうか? 少々頭が混乱していて、ややこしい文章になってしまい申し訳ありません<(_ _)>

関連するQ&A

  • 初期処理について

    前の質問で以下のコードを教えてもらいましたが、 HTMLの<head>に以下を書いてもdocument.writeは実行されます。 <script> a=1; b=2; function hoge(){ var a=3; b=4; c=5; } hoge(); document.write("a="+a+"<br>"); document.write("b="+b+"<br>"); document.write("c="+c+"<br>"); </script> それで思ったんですけど、後で使い回す画像とかは 関数の外で書いて最初に読み込むとかは、実は常識なのですか? こんな方法で初期処理を記述すればいいんでしょうか。 今は初期処理用の関数をonload時に実行させています。 VBAはこんな真似できなかったと思います。

  • 関数内での繰り返し処理の結果を配列で受け取りたい

    関数内でfor文で繰り返し処理を行い、 結果を配列として返すような関数を書きたいと思っています。 function hoge(){ var a = [1,2,3,4]; for (var i=0; i < a.length; i++){ a1 = "a" + i; var arr = new Array(); arr.push(a1); } return arr; } しかし、以下のように 関数hogeの結果を変数bで受け取ってみると、 配列の最後のデータしか表示されません。 var b = hoge(); alert(b); //a3のみが表示される a0, a1, a2, a3と表示されるようにするには、 どうしたらよいでしょうか。

  • Javascriptで数値の和を求める際の処理

    宜しくお願いします。 下記のプログラムの場合、 a,b,c の何れかの値が一つでも未入力の場合、 計算結果が表示されません。 未入力の場合は「0」とみなして、結果を表示させるには、 どの様にしたらよろしいでしょうか。 ご教授ください。 <script> var sum = 0; sum += a; sum += b; sum += c; var result = sum; var x = result; var y = myFormatNumber(x);function myFormatNumber(x) { var s = "" + x; var p = s.indexOf(".");if (p < 0) { p = s.length; } var r = s.substring(p, s.length); for (var i = 0; i < p; i++) { var c = s.substring(p - 1 - i, p - 1 - i + 1); if (c < "0" || c > "9") { r = s.substring(0, p - i) + r; break;}if (i > 0 && i % 3 == 0) { r = "," + r; } r = c + r; } return r; } document.write(y); </script>

  • リストボックスに追加した全ての値を取得したいのですが・・・

    No.172288で質問したものですが まだJavaScriptを勉強しはじめたばかりでまた壁にぶつかってしまいました。 Bのリストボックスの値をAに追加して他のページにPOSTで送りたいのですが Aに追加された値をすべて送りたいのです。 それで、まずすべての値をとれるかどうかを確認するためにSubmitボタンを押して すべてを表示させるものを作ってみたのですが、どうしても 一番目(つまりiが0のAAAAA)しか表示できません。 エラーも出ないのでどこが間違っているのかがわからないのですが どこが間違っているのでしょうか。 何度もすみませんがよろしくおねがいします。 <html> <head> <title></title> </head> <script type="text/JavaScript"> <!-- function addItem() { A = document.X.A; B = document.X.B; for(var i=0;i<B.options.length;i++) if(B.options[i].selected) A[A.options.length] = new Option(B.options[i].text, B.options[i].value); } function func(){ for(var w=0;w<A.options.length;w++) document.write(A.options[w].text); } // --> </script> <body> <form name="X"> <select size="5" multiple name="A"> </select> <input type="button" value="Copy" onClick="addItem()"> <select size="5" multiple name="B"> <option>AAAAA</option> <option>BBBBB</option> <option>CCCCC</option> </select> </form> <form name="Y"> <input type="button" value="Submit" onClick="func()"> </form> </body> </html>

  • 2件一組の文章をランダムに表示する。

    お世話になっております。 早速ですが、A~Dの文章を2件ランダムに表示させたいです。 更新の度に表示される文章を変えたいのです。 ランダムに文字を並べ替えるコトは出来たのですが、 ソコから2件だけ抜き出すのができません。 <script language="javascript"> arr = ["ほげほげA","ほげほげB","ほげほげC","ほげほげD"]; function a(){ for(i=0; i<arr.length; i++){ k = i; k = Math.floor(Math.random()*arr.length); tmp = arr[i]; arr[i] = arr[k]; arr[k] = tmp; } } function b(){ a(); for(j=0; j<arr.length; j++){ document.write(arr[j]); } } b(); </script> ■1回目 ほげほげC ほげほげA ■2回目 ほげほげA ほげほげD のような感じです。 ご助力お願いいたします!

  • 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だと作動しません。 対応してないのでしょうか? 宜しくお願いいたします。

  • func.arityで、undefined

    とほほのjavascriptで勉強しているのですが http://www.tohoho-web.com/js/function.htm 関数オブジェクトのfunc.arityのところ 関数が要求する引数の個数を返します。 とあるのに、 function goukei(a, b, c) { return(a + b + c); } n = goukei.arity; document.write(n); このコードを書いて実行しても 引数の個数の3ではなく、undefinedが表示されます。 ちゃんと引数は3個だし、functionで定義した関数も、document.write文の前に宣言してあり ぱっとみ問題ないように思われるのですが、どうしてundefinedと表示されるのでしょうか。

  • ABCD・・・Z と表示しようとして

    <script> for(var i='A';i<='Z';i++) { document.write(i); } </script> としましたが結果は A となりました。 ABCD・・・Z と表示するにはどうしたらいいでしょうか? Perlのように簡単にはいかないのでしょうか?

  • javascript

    var sum = function(){ var result = 0; for(var i = 0; i < arguments.length; i++){ var tmp = arguments[i]; result += tmp; } return result; } document.writeln(sum(1, 3, 5, 7, 9)); このプログラムと function sum(){ var result = 0; for(var i = 0; i < arguments.length; i++){ var tmp = arguments[i]; result += tmp; } return result; } document.writeln(sum(1, 3, 5, 7, 9)); このプログラムでは実行結果は同じですが、 どちらのほうが良いプログラムなのでしょうか?

  • <body>にwindow.onload = functionを2つ設定すると、最後に書いたイベントだけが実行されてしまいます。

    <body>タグにonloadイベントを実行させる2つの外部jsを<head>内に設置し実行すると、 最後に記述したイベントだけが反映されてしまいます。 http://blog.webcreativepark.net/2008/02/26-185844.html を参考にいろいろといじってはみたのですが、 function addEvent(elm,listener,fn){ try{ elm.addEventListener(listener,fn,false); }catch(e){ elm.attachEvent("on"+listener,fn); } } js初心者でして、上の関数の中にどのように記述をすれば良いのかわかりません。 IE6・IE7・safariで動作させるには、実際にどのようなソースを書けばいいのでしょうか。 どなたかご教授いただけますでしょうか。 <head>内の外部jsは、以下のように記述しました。 <script src="/A.js" type="text/javascript"></script> <script src="/B.js" type="text/javascript"></script> </head> 外部jsのソースは以下になります。 //A.js window.onload = function() { var blur = function () { this.blur() }; for (var i = 0; i < document.links.length; i++) document.links[i].onfocus = blur; } //B.js window.onload = function() { prepZooms(); insertZoomHTML(); zoomdiv = document.getElementById(zoomID); zoomimg = document.getElementById(theID); } 以上になります。宜しくお願い致します。