uhyohyo.net

JavaScript初級者から中級者になろう

基礎第四回

関数の定義

久しぶりに関数という言葉が出てきました。関数は、基礎第一回alertが出てきました。今までよく使っています。

では、定義とはどういうことでしょう。この場合、関数を自分で作ることです。関数は、もともとあるものの他に(もちろんalert以外にもたくさんあります)、自分で作ることができます。次のサンプルを見てみましょう。

function aaa(){
    alert("test");
}
aaa();
        

「test」というアラートが出ました。

4行目の「aaa();」の行で、aaaという関数を呼び出しているようです。このaaaが、今回自分で作った関数です。

1行目から3行目がなにやら怪しいですね。またまた見たことも無い形だと思います。これは新しい構文です。

function 関数名() {
    文(いくつでも)
} 

このようにすると、「関数名」という名前の関数が新しくできます。上のサンプルでは「aaa」でしたね。

どんな処理をする関数なのかを決めないとどうしようもないわけですが、それは{ 〜 }の中に書きます。

というのも、このようにして作った関数が「aaa()」のように呼ばれると、さっきの{ 〜 }の中の処理が行われます。function 関数名(){ 〜 }はあくまで関数を作っているだけなので、その中の処理は関数が呼び出されたときしか行われません。つまり、プログラムが上から進んできて、この形(関数宣言といいます)の部分を通過してもそこで何か起きるわけではないということです。

さて、今回の場合、「aaa();」として関数aaaを呼び出すと、定義されたalert("test");が実行されます。{ 〜 }の中の処理が終わるとaaa()の処理が終了したことになります。

関数の主な意義は繰り返し使えることにあります。例えば大規模な処理があるとして、プログラム中で同じ処理を3回使いたいとしたら、同じプログラムを3回書かないといけないことになり無駄です。

このとき、その大規模な処理をひとつの関数にしておくと、その処理を使いたいときはその関数を呼び出すだけでいいので簡単です(ただし、実際のプログラムでは関数を機能ごとに小分けして、あまり一つの関数が大規模にならないように気をつけるものなので、大規模な処理をひとつにまとめるというより、機能単位で処理をまとめるというほうが実は適切です)。

引数のある関数

alertには、引数があります。しかし、さっき作った関数aaaには引数がありませんでした。自分で作った関数にも、引数を受け取らせることができます。

受け取らせるとは、その関数が与えられた引数を使うということです。次のサンプルを見てみます。


function aaa(abc){
    alert("引数は" + abc + "です");
}
aaa(5);
aaa(3);
aaa("test");

「引数は3です」「引数は5です」「引数はtestです」という三回のアラートが出ました。

最初の3行で関数aaaを定義し、次の3行で3回aaaを呼び出しています。今回、aaaに一つの引数を渡しているのが分かると思います。

さて、aaaの定義部分を見てみると、前回「aaa(){ 〜 }」だったのが「aaa(abc){ 〜 }」となっていて、括弧の中に「abc」というものがあります。

このabcは変数名で、aaaが呼び出されると、自動的に引数が代入されます

1回目のaaa(5);では、aaaの中で変数abcに5が代入されていることになります。同様に、2回目では3、3回目では"test"が代入されます。

また、引数が2つ以上ある関数も作ることができます。

function sum(aaa,bbb){
    alert(aaa + bbb);
}
sum(5,8);
sum("あああ","いいい");

実行すると、「13」というアラートと「あああいいい」というアラートが表示されました。

今回はsum関数を2つの引数で呼び出しています。sum関数の定義を見てみると、括弧の中に(aaa,bbb)というように変数が2つ記述されています。このように「,」で区切るのは、関数呼び出しのときと同じ形式です。

それぞれの変数にそれぞれの引数が代入されます。順番もそのままです。つまり、1回目では、aaaに5が、bbbに8が代入されています。2回目では、aaaに"あああ"、bbbに"いいい"が代入されています。

関数の中で変数を使う

関数の中でも、当然引数が代入された変数以外にも自由に変数を使うことができます。次のサンプルを見てみましょう。


function aaa(){
    a = 3;
    alert(a);
}
a = 5;
alert(a);
aaa();
alert(a);

「5」「3」「3」とアラートが表示されます。

今までの解説の知識でなんとか分かると思います。最初の4行は関数aaaの定義で、その次の行はaに5を代入しています。そのため、その次の行では5のアラートが表示されます。

次の行で関数aaaを呼び出しています。aに3を代入し、アラートでaを表示しているので、当然3が表示されます。

aaaの処理が終わり、次の行に進むと、またaをアラートで表示しています。さっき3を代入したので、また3が表示されます。

何も問題はありませんね。では、次のサンプルはどうでしょう。

function aaa(){
var a = 3;
    alert(a);
}
a = 5;
alert(a);
aaa();
alert(a);

「var」という謎の3文字が追加されています。

なんと、さっきと結果が変わりました。「5」「3」「5」と表示されます。

原因はもちろん「var」の行でしょう。実は、このように文の先頭に「var」をつけて代入した変数は、ローカル変数になります。

ローカル変数とは、その関数の中だけで通用する変数のことです。というより、名前が同じでも、その関数の中だけ別の変数のようになります。

このソースの動作をみてみましょう。「a = 5;」の行でaに5が代入され、次の行でそれを表示するところまでは同じです。

次の行でaaaが呼び出されると、同じようにaに3を代入しますが、ここで、このaはローカル変数になります。さっきまでのaとは別物で、この関数aaaの中だけで通用する新しいaです。

つまり、aaaの中で変数aに何をしようと、もともとのaとは別物なので、影響はありません。

さて、そのローカル変数のaに3を代入し、それを表示するので、3が表示されます。

ここで、aaaの処理が終了します。この時点でローカル変数のaはなくなります。

さて、その次の最後の行ではaを表示します。このaは、最初のaと同じaなので、5が表示されるというわけです。

ローカル変数とグローバル変数

上のサンプルのような場合、関数の外で使われる変数(ローカル変数に対してグローバル変数といいます)とローカル変数が同じ名前だったので、多少はローカル変数を使う意味が分かったと思います。

関数の外で使われる変数と関数の中で使われる変数の名前は一致しないことが多いと思いますが、だからといってローカル変数を使う必要が無いかというと、そうではありません。

関数の中で使う変数は、ローカル変数にするのが鉄則です。

関数というのはひとかたまりの処理なので、処理はその関数の中で完結するべきです。つまり、関数の外と関わりを持たず、与えられた引数に応じて処理を行うだけなので、グローバル変数を使う必要はないということです。逆に、関数がグローバル変数を書き換えてしまうと、関数と直接関係ないところで副作用が生じることになり、プログラムが理解しにくくなったりバグの原因になるのです。場合に応じて例外もありますが、関数の中で作る変数は全てローカル変数にするものだと考えて問題ないでしょう。

var a=3;
alert(a);

ところで、このコードは、ごく普通に変数aに3を代入してそれを表示するコードです。

しかし、関数の中でもないのに、varをつけて変数に代入しています。関数の中ではないので、varがついていますがあくまでグローバル変数です。このように、関数ではないところでvarを使うことも可能ですが、意味はありません。ただ、varをつけると変数を新しく作っているのだということが一目瞭然なので、この処理ではこういう新しいグローバル変数を作って使っていますよ、ということを(プログラムを見る人に)示す効果があります。ですから、プログラムをわかりやすくするためにもできるだけつけておきましょう。

戻り値のある関数

今度は戻り値のある関数を作ってみましょう。

その前に、戻り値の解説をします。前に演算子が値を返すということを解説しましたが、実は関数も値を返すことがあります。

しかし、今まで戻り値がある関数を解説したことがありません。というより、関数もalertしか解説したことがありません。そこで、もともとある新しい関数を紹介します。

parseInt

var a = parseInt("12"); alert(a + 5);「17」というアラートが出ますね。「parseInt」が新しい関数です。

しかし、場所が今までと違いますね。aに「parseInt("12")」を代入しています。

演算子が計算結果に置き換わるように、関数をこのように使った場合、関数が返した戻り値に置き換わります。

つまり、parseInt("12")がその返り値に置き換わり、それがaに代入されるということになります。

さて、それではparseIntの返り値が何かですが、この関数は、引数を数値に変換して返します

数値に変換するとはどういうことかというと、parseIntに渡した引数は「"12"」という文字列です。しかし、この文字列は数字を表す文字列です。だから、数値として使いたいときがあります。

そうした場合に、parseIntを使うと数値として得ることができます。つまり、こういうことです。

var a = parseInt("12");
↓
var a = 12;
        

parseIntの次の行でa+5を表示していますが、aは12なので、12+5=17で17が表示されるというわけです。

parseIntが使えないと、こういう場合、

alert(a + 5);
↓
alert("12" + 5);
↓
alert("125");
        

というようになり数値の計算ができません。今回の場合特に意味はないですが、画面上の入力ボックスに数を入力してもらう場合など、それを文字列でしか得ることができません。そういったときに、このparseIntが必要になります。

戻り値のある関数を自分で作る

それでは、戻り値のある関数を自分で作る方法を解説します。次のサンプルを見てみましょう。

function sum(a,b){
    return a+b;
}
alert( sum(100,10) );

「110」というアラートが出ます。

alertの行で、関数sumを呼び出してその戻り値を表示していることが分かると思います。

さて、sumの中を見てみると、returnという怪しいものがあります。これが戻り値を返すはたらきをしているのです。

このreturnは、returnの後の値を戻り値として返すものです。この場合、戻り値はa+bということになります。

つまり、sumが呼び出されると、引数は100と10なので、a+bは100+10=110となり、関数sumは110を返します。それをalertで表示するので、110が表示されたというわけです。

また、returnがあると、関数はそこで終了します。それを応用し、次のような使い方ができます。

function aaa(){
    return;
    alert("aaa");
}
aaa();

これは、関数aaaを作って呼び出しています。

しかし、aaaの中にalertがあるのに、アラートは表示されません。そう、その前の行にreturnがあるからです。

このように、returnを使った場合、関数が終了します。returnで関数が終了したので、その次のalertは呼び出されなかったのです。ちなみにこの場合返り値はありませんが、その場合関数は何も返さないということになります(厳密には少し違いますが、ここでは解説しません)。