アプリ版:「スタンプのみでお礼する」機能のリリースについて

javascriptの関数内で使われるreturnの解説で、
『関数を呼び出すと処理が関数のブロック内に移りますが、ブロック内でreturn文が実行されると関数内の処理は終了し、return文の後に記述された式を評価した結果が関数の呼び出し元に返されます。関数呼び出しを「変数名 = 関数名(..)」のように記述しておけば、関数から返された値を変数に代入することができます。 』
と説明されています。

上記の説明に出てくる
「return文の後に記述された式を評価した結果が関数の呼び出し元に返されます」
「関数から返された値」
という意味がよく分かりません。

↓コードの例で例えるとブラウザ側はどういう読み方をするのでしょうか。

<script type="text/javascript">
function kansuSPadd(para){
rc = "";
for (i = 0; i < para; i++){rc = rc + " ";}
return rc;
}
//(1)
for (i = 0; i <= 8; i++){
document.write(kansuSPadd(i) + "Welcame to Chaichan's Page <br>");
}

//(2)
for (i = 8; i >= 0; i--){
document.write(kansuSPadd(i) + "Welcame to Chaichan's Page <br>");
}
</script>


自分の考えではreturn rc;がない場合のときは、
(↓はreturn rc;がない場合の自分考え方です)
(1)ページを開く
(2)ブラウザ側は
(3)(1)のforを読む
(4)(1)のforでi=0のときdocument.write(kansuSPadd(0) + "Welcame to Chaichan's Page <br>")でfunction内では全角空白が1つ出力
(5)また(1)のforを読む
(6)(1)のforでi=1のときdocument.write(kansuSPadd(1) + "Welcame to Chaichan's Page <br>")でfunction内では全角空白が2つ出力


これを(2)のforの最後まで繰り返す

↑という感じです。
なぜreturnが必要なのか分かりません。

A 回答 (4件)

No2ですが、ちょっと間違いをしてしまいました。



よく見たら、

// (1)
// (2)

のFORループは kansuSPadd() 関数の{}の範囲に入っていませんでしたね。

なので、読み込まれた時点で(1)(2)のForが実行されますね。kansuSPadd()は、(1)(2)のForループで呼び出されているので、その時点でかかれますが、

ただNo1さんも指摘していますが、

document.write()は自分自身を書き換えるので、最初の1回目で機能しなくなります。

なお、通常、open() とclose()を実行しないと書き込まれません(特にIEでは)。

さらに return()を実行すると、値を返すだけでなく、kansuSPadd()の処理が、そこで終了するので、いずれもkansuSPadd()のFORは1回のみのループです。 なのでfor を終了してからreturn()です。

このことから、returnには2つ意味があります。値を返すのと、途中で処理をやめ、呼び出し元に処理を戻す。

なので、途中で呼び出されるときは、検証結果によっては、後は処理しないで抜けたい、なんてときに使います。


NO2のコメントは、半分はただしいので、あしからず(コードをよく見ていませんでした)。

なので、このコードはサーバー側で実行されるスクリプトなら、実現性がありますが、クライアントでは・・・

値をだけなら、グローバル変数か、HTMLオブジェクトに格納する方法、があるので、それで間に合いますが、

よくあるのが、値だけでなく、オブジェクト、を返す事も可能です。

return funciton(a, b){
a -b;
};

呼び出し元が var a = me(); だと値が戻るわけでなく、aに新たなる関数(メソッド)を作った事になります

また

return new kansuSPadd();

なんてすると、C++的に言えば、新しいインスタンスが作成されたことになります。

前回の検索リンクのユーザー定義関数の詳細を掲載していることろは、JavaScript1.3以降の新しいやり方が掲載されているので、return の使い方で、より、オブジェクト指向の強い階層化された、又はクラス定義に似たやり方を提供しています。 特に今のフレームワークには、エクステンドなるものがあり、階層化されたクラス定義のメソッドやプロパティを継承したり、付け加えたりと、

まるっきり C++やVB、Javaと似たような事が、擬似的にできます(あくまで似せているだけで、その機能は本来ありません)。
    • good
    • 0

実際に『return rc; がない場合』を試してみれば、予想通りにいかないことが明らかなはずですが。

と言うか、それはちょっとしたバグコードなので(これだけなら「たまたま」うまく動きますが)、参考にしてはダメです。

変数は必ず var 宣言してから使うようにして下さい。これを疎かにする JavaScript 入門書がたくさんありますが、後で泣きますよ。

本題。例えば、下のように書いたとき、rc が何であるか分かりますか。

// A
for (var i = 0; i <= 8; i++){
 var rc = '';
 for (var j = 0; j < i; j++) {
  rc += '\u3000';
 }
 document.write(rc + "Welcame to Chaichan's Page <br>");
}

これを下のように変形してみましょう。

// A'
for (var i = 0; i <= 8; i++){
 var tmp;
 kansuSPadd: {
  var para = i;
  var rc = '';
  for (var j = 0; j < para; j++) {
   rc += '\u3000';
  }
  tmp = rc;
 }
 document.write(tmp + "Welcame to Chaichan's Page <br>");
}

ここで、kansuSPadd: はブロック {...} につけられたラベルで、今は何の意味もありません。単に分かりやすさのためです。注目してほしいのは、kansuSPadd ブロックの外にある i を、ブロックの冒頭で para が受け取っていることです。そして、para をもとに計算された rc を、ブロックの最後に一時変数 tmp が受け取っています。ここで、もし tmp が rc を受け取らなかったらどうなるか、自分の目で確かめて下さい。

さて、このままでは色々面倒くさいので、kansuSPadd ブロックを kansuSPadd 関数として for 文の外に出してしまいましょう。

// B
for (var i = 0; i <= 8; i++){
 var tmp = kansuSPadd(i);
 document.write(tmp + "Welcame to Chaichan's Page <br>");
}

function kansuSPadd (para) {
 var rc = '';
 for (var j = 0; j < para; j++) {
  rc += '\u3000';
 }
 return rc;
}

kansuSPadd 関数の外にある i を、関数内の para が受け取る。これを引数と言います。para をもとに関数内で計算された rc は、return されることで関数外の tmp が受け取れるようになる。これを戻り値と言います。結果は上と同じになるはずです。return がない場合、当然 tmp が受け取るものもありません。その場合はどうなるかを確認して下さい。

最後に、この場合は戻り値を使うのに一時変数 tmp を経由する必要もないので、tmp を消してしまいましょう。また、kansuSPadd 関数を for 文の外に出しましたので、関数内では for 文で使われているのとは別の i を 宣言して使うことができます。

// B'
for (var i = 0; i <= 8; i++){
 document.write(kansuSPadd(i) + "Welcame to Chaichan's Page <br>");
}

function kansuSPadd (para) {
 var rc = '';
 for (var i = 0; i < para; i++) {
  rc += '\u3000';
 }
 return rc;
}

これで終わりです。

補足:JavaScript には(1.7-1.8 を除き)ブロックスコープがありませんので、厳密には A' と B は同じではありません。A' は動的スコープ(ただし似非)、B は静的スコープです。
    • good
    • 0

あなたが問題にしているのは、初心者が、最初に起こす、勘違い又は誤解による疑問と思われます。



だからといって心配することはありません。遠い過去、15年くらい前の人はみな、あなたような勘違いと言うより、認識できなかったので、クライアントサイドスクリプトとサーバーサイドスクリプトがなぜ必要なのか、まったく理解できず、なんでそんな、

遊んでいるような物作っているんだ。そんな余計なコード入れるな!
(マウスオーバーで変化するような物は余計でフザケテイル。なんて古い業界だったんですよ)

とよく上司にいわれたものです。開発レベルでも、そんな認識だったのです。
(今じゃ考えられませんね)

下記のURLなどを参考にし、ブラウザレベルの実行単位を認識してください。

http://d.hatena.ne.jp/m-hiyama/20050829/1125275359

http://search.yahoo.co.jp/search?p=Javascript%E3 …

本題ですが、

まず認識しないといけないのは、クライアントサイドもサーバーサイドもプログラムによるデーターの出力先が「標準出力」となった時が、ブラウザへの出力となります。つまり、サーバー側だと、echo とかprintとかコマンドレベルの出力先は通常、標準出力となっています。クライアントだと、

document.wite となって初めて、ブラウザに出力になります。又は、DIV.innerText = "aaa";となって初めて、HTMLオブジェクトに書き込まれます。

ではreturnで返す場所はどこか、と言うことですね。それは呼び出し元に返すのであって、ブラウザ及びHTMLオブジェクトには返していないのです。

>(3)(1)のforを読む
> (4)(1)のforでi=0のときdocument

これは、正しいと言えますが、認識が間違っています。これは、読み込みの動作(実行単位)で、コンパイルと同じ行為を行っているにすぎません。よみこまれた時点でfunction() が実行されると思っているようですが、そうではありません。

function()内は、読み込まれるだけで、実行は、function()を呼び出したときに実行されるわけです。function()以外の<script>内の物は実行されますが、function()は呼び出されて初めて実行されるわけです。実効命令は

function();

です。上記は匿名関数と特に呼ばれています。これに名前をつけると
function me ()

とすれば、

me();

と言う具合に関数名に”()”を付けると実行する事ができます。ユーザー定義関数を呼び出して実行しないと、実行されません。なので、あなたの、(3)までは正しいのですが、その後は、読み込まれますが、何も実行されないので空白はどこにも出力されません。

document.getElementById("divobje").innerText = kansuSPadd();

などを、
------
}
</script
----------
の間に書くと

}
document.getElementById("divobje").innerText = kansuSPadd();
</script>

初めて、それぞれのfor() ループが実行されます。問題のreturnの値は divobje と言うIDがついたHTMLオブジェクトに挿入されます。

プログラムでは、必ずどこに出力するか、どこに返すかと言うのを意識して作る必要があるわけです。

クライアンドサイドでは、特にHTMLオブジェクトに対して特別に、書き込む命令を書かないと、ブラウザには出力されません。

この仕組みはサーバーサイドスクリプト(CGIなどPHPとか、exeファイル、ASP .NET, Java)でも同じです。HTMLの中にコードを書く物と(埋め込み)、スクリプトファイルの中にHTMLを記述する2通りのやりかがあります。
    • good
    • 0

> function内では全角空白が1つ出力



「全角空白を1つ出力」を function内でしているように見えるのですか?
出力のコードが何処だか指摘できますか?
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!