関数スコープを抜けると初期化されてしまう

このQ&Aのポイント
  • 関数スコープを抜けると変数が初期化されるため、roundNumの値がリセットされてしまいます。
  • roundNumの中身が関数内の処理が終了すると破棄されてしまうため、次回の呼び出し時には初期値が設定されます。
  • 関数スコープ内で変数を保持するためには、関数の外で変数を宣言し、関数内でその変数を使用する必要があります。
回答を見る
  • ベストアンサー

関数スコープを抜けると初期化されてしまう

小数点第X位で四捨五入する。使いまわす関数を作り複数の計算式で利用しようと思ったのですが変数roundNumの中身が関数が終了すると関数内の小数点第一位までという処理がなかったことになり、結局元の小数点をいくつでも出す状態に戻ってしまいます。 この理由は関数スコープがあるのでroundNumが同じ名前でも別変数になっているからでしょうか? それとも関数スコープを抜けた瞬間にこの除法は破棄されてしまうからでしょうか? このような処理をどうやって関数化しますか?関数化自体を諦めて同じコードをコピペしまくるしかないのでしょうか? var roundNum; (function () { function round(roundNum) { var decimalPoint = 1 ; roundNum = Math.floor( roundNum * Math.round( 10, decimalPoint ) ) / Math.round( 10, decimalPoint ) ; } ~

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

  • ベストアンサー
回答No.8

>回答No.7 amanojaku1 >function round(roundNum) { >var decimalPoint = 1 ; >roundNum = Math.floor( roundNum * Math.round( 10, decimalPoint ) ) / Math.round( 10, decimalPoint ) ; >return roundNum >} 「function round(roundNum) 」関数の「return roundNum」にセミコロンが抜けてました(下記訂正)。 function round(roundNum) { var decimalPoint = 1 ; roundNum = Math.floor( roundNum * Math.round( 10, decimalPoint ) ) / Math.round( 10, decimalPoint ) ; return roundNum; } 帰り値自体を式にしても良いですね(下記訂正)。 function round(roundNum) { var decimalPoint = 1 ; return Math.floor( roundNum * Math.round( 10, decimalPoint ) ) / Math.round( 10, decimalPoint ) ; }

その他の回答 (9)

回答No.10

> どんどん増やしていく方法しか思いつきません。 関数の作り方、使い方を正しく理解されていないのかもしれませんので 念のため、補足させて頂きます。 関数とは特定の機能をカプセル化するものなので、 関数の結果を代入したい変数が増えたからといって 関数を増やしたり、引数を増やしたりする必要はまったくありません。 また、関数をコールする側の引数の変数名と 関数の定義で受け取る 変数名は、一致している必要はありません。 なので、たとえば function func1(xxx) {  xxx = 計算式;  return xxx; } のように関数を用意したとしても、これをコールする側の引数の変数名は xxxである必要がありません。 よって、上記のfunction func1(xxx) {~} を コールする部分では  b = func1(a); のように引数に、xxxでなくaの値を引数で渡してもよいのです。 これと同じように、小数点以下1桁で四捨五入した結果を、return値で戻してくれるように function round(引数となる変数名){  ~小数点以下1桁で四捨五入する計算式~(略);   return リターンする変数名; } を1つだけ用意して、 これを roundNum = round(roundNum); と使えば、 roundNumが四捨五入されますし、 addResult = round(addResult);と 使えばaddResultが四捨五入されます。 上記のようにすれば、結果を代入したい変数が増えたからといって function round()の引数や戻り値を増やす必要はまったくありません。 ただしfunction内で宣言したローカル変数や引数の変数への代入でなく グローバル変数への代入があると、話がややこしくなります。 なので、functionのなかでは できるだけグローバル変数への代入はしないように コーディングして、関数の中身を知らなくても使えるようにブラックボックス化するのが 理想です。

okweb12345
質問者

補足

ありがとうございます。 そうでした。呼び出し元に渡されるだけなので、渡すものを指定するだけでもらう側に変数名をつける必要は無かったですね。 関数の呼び出し元にだけっ実行結果が渡されるだけなので、他には影響を与える事はないですね。

回答No.9

> その後下記のように複数の計算をこの関数で、共通に四者五入するようにしたいのですが、また疑問が出てきました、 > それぞれの計算の値が入った変数名が違いので、下記のように複数にしないといけないと気づきました。 関数化するというのは、カプセル化です。 汎用的に使えるようにしてある特定の計算をおこなう関数を用意したときに それに同じ計算を複数の変数に対して行いたいときには、 関数の引数をどんどん増やすということはしないで コール側で、複数コールすればよいだけです。 今回なら、 roundNum = round(roundNum); addResult = round(addResult); とするだけのことですね。 配列に入れてあるなら forループでこれをやればよいので、もっと簡単ですね。

okweb12345
質問者

お礼

function round(roundNum, addResult) { return [roundNum,, addResult]; } これをどのように変更するのでしょうか? どんどん増やしていく方法しか思いつきません。

回答No.7

>関数スコープを抜けた瞬間にこの除法は破棄されてしまうからでしょうか? そうです。 確かにグローバルとローカルの変数名が同じだと初心者には混乱の元になってしまいがちでしょう。 下記は即時関数は使ってません。 <script type="text/javascript"> var foge; function round(roundNum) { var decimalPoint = 1 ; roundNum = Math.floor( roundNum * Math.round( 10, decimalPoint ) ) / Math.round( 10, decimalPoint ) ; return roundNum } foge = round(1.23456789); alert(foge); </script>

  • chachaboxx
  • ベストアンサー率23% (412/1777)
回答No.6

「ここで四捨五入後の数値を代入しているので…」がややこしくなる原因です。"その変数名"で代入された場所がスコープ内なので、抜けたあとは不定な状態でもいいだろ 的な考え方ですね、言語側の思考は。だからスコープ外でも代入した値を使うから、勘違いしないように、とりあえずややこしくなるからスコープ内ではその変数名を使わずに、"param1"とかの別の名前で作業してから、結果を引数に格納して下さいな とするわけです。分からず屋も上手に使えば素直ですよ。(笑)

回答No.5

> 引数としてfunction round(roundNum)とあるので、 > これでroundNumがローカル変数として 宣言されたのと同等となります。 補足です。 これは、JavsScriptで文字列型や数値型の変数を functionの引数にした場合は、 ”値渡し”になるからですが、 引数がオブジェクト型の場合だけは、”参照渡し”になるので、 function内でオブジェクトの内容を変更すると、そのfunctionをコールした側の オブジェクトも変更されます。 (つまりオブジェクト型の引数の場合だけは、例外です)

  • chie65535
  • ベストアンサー率43% (8508/19344)
回答No.4

>こちらの仮引数roundNumがあるのが問題という事でしょうか? グローバル変数に代入されない原因は、仮引数の名前が「roundNum」になっているからです。 var roundNum;←どこからも参照も代入もされない function round(roundNum←関数内への代入はコレに対して行なわれる) { var decimalPoint = 1 ; roundNum←関数への引数に代入される = Math.floor( roundNum←関数への引数を参照する * Math.round( 10, decimalPoint ) ) / Math.round( 10, decimalPoint ) ; } >ただそうであっても >ここで四捨五入後の数値を代入しているのでroundNumの中にこの数値が入り、この変数を指定すればどこでもこの数値を計算に使えるのではないですか? いいえ使えません。 行なったのは「関数内だけで有効なローカル変数への代入」なので、関数から抜けた瞬間、代入した結果も、代入した変数も「破棄」されます。 この変数への代入が及ぶのは「関数内」だけです。関数の外では「代入されてない」ので「初期値のまま」です。 >function round() { >var roundNum;こうなるという事ですよね? >var decimalPoint = 1 ; >roundNum = Math.floor( roundNum * Math.round( 10, decimalPoint ) ) / Math.round( 10, decimalPoint ) ; >} 最初の質問文の状態とは違う結果になる、異なるプログラムになります。 以下のように、結果がundefinedになります。 function round() { var roundNum;←同名のローカル変数の宣言 var decimalPoint = 1 ; roundNum←ローカル変数にundefinedを代入しようとする = Math.floor( roundNum←ローカル変数から参照してundefinedになる * Math.round( 10, decimalPoint ) ) / Math.round( 10, decimalPoint ) ; }

回答No.3

どんな言語でも、ほとんど同じですが、 グローバル変数とローカル変数に 同じ変数名を付けることができます。 この場合、その変数の入っているメモリは それぞれ別物です。 つまり、 ローカル変数が宣言されたスコープ内で、その変数の内容を変更しても そのスコープの外で宣言された変数(この場合グローバル変数)の 内容は変わりません。 たとえば、 var a = 1; ←★1グローバル変数a を1で初期化 function func1() { var a ;   ←★2ローカル変数a a= 2;  ↑このaは、★2のローカル変数a なので、ローカル変数aには2が代入されるが、   ★1のグローバル変数aは1のまま。 } func1(); で、function func1を実行しても、グローバル変数aは1のままです。 今回は、function round内でローカル変数としてのroudnNumの宣言はありませんが、 引数としてfunction round(roundNum)とあるので、 これでroundNumがローカル変数として 宣言されたのと同等となります。 よって、function roundのなかのローカル変数のroundNumに代入しても、 グローバル変数のroundNumは変更されない ということになります。 function round(~) の最後で return roundNum; として、functionが値を戻すようにして これをコールしているところででroundNum = round(roundNum); と して、グローバル変数に代入するようにすると 分かりやすいと思いますよ。 (functionの内部でグローバル変数に上書きしてしまうと、  functionの汎用性(他での使い回し) が下がりますので)

okweb12345
質問者

お礼

>>> function round(~) の最後で return roundNum; として、functionが値を戻すようにして これをコールしているところででroundNum = round(roundNum); と して、グローバル変数に代入するようにすると 分かりやすいと思いますよ。 (functionの内部でグローバル変数に上書きしてしまうと、  functionの汎用性(他での使い回し) が下がりますので) ありがとうございます。 仰る通り、 function round(~) の最後で return roundNum; として、functionが値を戻すようにして これをコールしているところででroundNum = round(roundNum); とすることでうまくいきました。 returunを使うことが今までなく、どんな時に使うのかと思っていたのですが、 関数内の処理を関数外で引き継ぎことが出来ないので、returunで処理結果を呼び出しもとに渡せば、 関数内の処理を関数が終わったら破棄されずに次の処理に引き継つぐことが出来るのですね。 グローバル変数について function内の変数とそれ以外の変数は同じ名前でも全く別物なので、 関数スコープ内での、関数外の変数への再代入は不可能なのですよね。

okweb12345
質問者

補足

その後下記のように複数の計算をこの関数で、共通に四者五入するようにしたいのですが、また疑問が出てきました、 それぞれの計算の値が入った変数名が違いので、下記のように複数にしないといけないと気づきました。 function round(roundNum, addResult) { return [roundNum,, addResult]; } もちろん計算の方の変数をすべてroundNumとしてします強硬策もありますが、それだと、変に影響を及ぼす可能性があり、出来ればもっとスマートなやり方があればと思うのですが、ご存知でしょうか?

  • chachaboxx
  • ベストアンサー率23% (412/1777)
回答No.2

人間的な文法解釈と言語仕様の優先順位の違いです。不自然でも結果を得られる様にコーティングするしかないです。

okweb12345
質問者

お礼

var roundNum; (function () { function round(roundNum) { var decimalPoint = 1 ; roundNum = Math.floor( roundNum * Math.round( 10, decimalPoint ) ) / Math.round( 10, decimalPoint ) ; } こちらの仮引数roundNumがあるのが問題という事でしょうか? function round(これroundNum) { var decimalPoint = 1 ; roundNum = Math.floor( roundNum * Math.round( 10, decimalPoint ) ) / Math.round( 10, decimalPoint ) ; } function round() { var roundNum;こうなるという事ですよね? var decimalPoint = 1 ; roundNum = Math.floor( roundNum * Math.round( 10, decimalPoint ) ) / Math.round( 10, decimalPoint ) ; } ただそうであっても roundNum = Math.floor( roundNum * Math.round( 10, decimalPoint ) ) / Math.round( 10, decimalPoint ) ; ここで四捨五入後の数値を代入しているのでroundNumの中にこの数値が入り、この変数を指定すればどこでもこの数値を計算に使えるのではないですか? 上記の認識でよいという事ですか? もう少し具体的に教えていただけないでしょうか?

  • chie65535
  • ベストアンサー率43% (8508/19344)
回答No.1

関数の仮引数はローカル変数です。 以下のように書いたのと同じ意味になります。 var roundNum; (function () { function round(parameter) { var decimalPoint = 1 ; parameter = Math.floor(parameter * Math.round( 10, decimalPoint ) ) / Math.round( 10, decimalPoint ) ; } こう書くと「roundNumに対して、何もしてない」という事が良く判ると思います。どう見ても「宣言だけして、代入も参照もしてない」ですからね。 「グローバル変数に結果を返したい」なら、以下のように書いて下さい。 var roundNum; (function () { function round(parameter) { var decimalPoint = 1 ; roundNum = Math.floor(parameter * Math.round( 10, decimalPoint ) ) / Math.round( 10, decimalPoint ) ; }

okweb12345
質問者

お礼

var roundNum; (function () { function round(roundNum) { var decimalPoint = 1 ; roundNum = Math.floor( roundNum * Math.round( 10, decimalPoint ) ) / Math.round( 10, decimalPoint ) ; } こちらの仮引数roundNumがあるのが問題という事でしょうか? function round(これroundNum) { var decimalPoint = 1 ; roundNum = Math.floor( roundNum * Math.round( 10, decimalPoint ) ) / Math.round( 10, decimalPoint ) ; } function round() { var roundNum;こうなるという事ですよね? var decimalPoint = 1 ; roundNum = Math.floor( roundNum * Math.round( 10, decimalPoint ) ) / Math.round( 10, decimalPoint ) ; } ただそうであっても roundNum = Math.floor( roundNum * Math.round( 10, decimalPoint ) ) / Math.round( 10, decimalPoint ) ; ここで四捨五入後の数値を代入しているのでroundNumの中にこの数値が入り、この変数を指定すればどこでもこの数値を計算に使えるのではないですか?

関連するQ&A

  • 変数の宣言をグローバルにしないと変数の参照が出来ま

    変数の宣言をグローバルにしないと変数の参照が出来ません。 ソース全体はカプセル化のために即時関数で囲っています。 function found内で小数点第三位までで四捨五入するようにする処理が共通なので関数化したのですが、 var gramNumを外で宣言しないと参照できずにgramNumが定義されていないと出てしまい困りました 関数スコープの影響だと思い宣言を外に出したのですが、それでも定義されていないと出て、 最終的にグローバル変数にしてやっとうまくいきました。 スコープは自分より上のスコープの変数は参照できるようですが if(xGramEmptyFlag === true) {ないの式がroundの上にあるvar gramNumを参照する場合、 if分の中にある式の一つ上のスコープなので参照できると思ったのですがなぜできないのでしょうか? varはブロックスコープがないので一つ上ではなく同じスコープにあることになるのでしょうか? ただその場合も同じスコープの変数は参照できるのではないのでしょうか?

  • エクセルの関数。お願いします!

    任意の桁数で四捨五入するROUND関数についてお願いします。 A1「5678.492」の数値。 (ア)小数点以下を四捨五入しなさい。 (イ)1の位を四捨五入しなさい。 =ROUND(A1,○)の○には何が入るんでしょうか?

  • round関数について

    試しにエクセルで次の計算をしてみてください。 -16.76 7.9 -11.45 -8.88 -1 4.26 33.78 以上を全部足します。つまり「=sum(a1:a7)」です。当然「7.85」になります。 次に四捨五入します。round関数で小数点第2位を四捨五入して、第1位まで表示させます。つまり、「=round(sum(a1:a7),1)」ということです。すると「7.8」を返しました。 ん?「7.9」なのでは?と思い、次にこんな計算をしてみました。 A・・・=round(sum(a1:a7),2) B・・・=round(A,1) つまり、Aでいったん小数点第3位を四捨五入させた上で、その値を今度はBで小数点第2位を四捨五入させ、最終的に小数点第1位まで表示させたわけです。すると、ちゃんと「7.9」を返しました。 なんでこんな風になるのでしょうか?どうして一発で「7.9」にならないのでしょうか?

  • 関数について

    一つのセルに、平均値を出し、それを四捨五入したいのですが、 関数を複合設定するにはどうすれば良いのでしょうか。 例えば、=AVERAGE(T4:T34)で出した平均値を、=ROUNDを使用して、小数点第1位で四捨五入したいのですが、式はどうすれば良いのでしょうか?

  • EXCEL 関数

    例えば =(E3-AVERAGE($E$3:$E$13))*10/STDEVP(E$3:E$13)+50 この数式の入った値は52.00187764 なのですが、これを四捨五入するROUND関数を使うとすればどのような数式になるか教えて欲しいのですが、先頭にROUNDをつけると()カッコの付け方等いまいちよくわかりません。 小数点第2位で四捨五入です。

  • エクセル関数を教えて下さい。

    ROUND関数で除算して、小数点以下を四捨五入させたセル(ROUND(A1/1.05、1))を合計する際、ROUND関数で求めた画面上の整数の合計をさせる関数を教えて下さい。SUM関数を使用すると、除算した小数点以下の数字にて集計されます。

  • 四捨五入について

    "1.005"を小数点第三位で四捨五入して、"1.01"にしたいのですが、 "Math.round(1.005*100)/100"だと1.005*100が100.4999999999998になってしまい、結果的に"1.00"が返されてしまいます。何か良い解決方法はないでしょうか?

  • 関数 ROUNDとセルの書式設定

    こんにちは。 EXCEL初心者です。 関数について、ふと思ったことがありましたので質問させてください。 ROUNDとか*UPや*DOWNという関数がありますよね? 調べてみるとこの関数の行う処理は、「値を指定した位で四捨五入する関数です。消費税の計算など小数点以下の位を四捨五入する時などに使えます」とのことですが、この処理は、「セルの書式設定」→「数値」で出来る設定と同じような気がするのですが、なにか違うのでしょうか? よろしければ「こんな使い方もあるよ」的なことを紹介していただけるとうれしいです。

  • エクセルの関数について

    こんにちは。 エクセル関数でわからないところがあるので、教えてください。 Round関数で、四捨五入の小数点以下の表示を切っています。 そうすると、その合計を取ると、実際は表示は小数点以下が 切れていても、元の数字は小数点が残っているので 合計を出した時に端数が合いません。 =IF(E5=0,"",G5) このG5に当たる個所が、Round関数が入っていて 合計が合いません。 ちなみにG5には、=ROUND(C6,2) こんな式が入っています。 C6の数値が小数点になっています。 分かる方、教えてください。よろしくお願いいたします。

  • 計算結果の処理について

    入力された数値に従って、計算をするというスクリプトを作成しています。 計算結果が2.27272727…と続くような場合が出てくるので、 小数点以下第何位を四捨五入するとか、第何位以下を切り捨てるといった数学関数はありますか? 調べてみても、以下3つぐらいしかありませんでした。 Math.ceil() Math.floor() Math.round() 宜しくお願いします。