uhyohyo.net

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

基礎第四回

このページの最終更新日:

関数の定義

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

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

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

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

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

1行目から3行目がなにやら怪しいですね。これが新しい構文です。

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

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

関数を作るなら、どんな処理をする関数なのかを決める必要がありますが、それは{ 〜 }の中に書きます。

このようにして作った関数が「aaa()」のように呼ばれると、さっきの{ 〜 }の中の処理が行われます。

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

なお、1〜3行目の関数定義の部分は、プログラムがそこを通過しても何も起きません。今回のプログラムは4行目のaaa();を実行し、その結果としてアラートが1回だけ出ます。

ちなみに、関数定義はどこに書いておいても構いません。関数を使うより後でも構いません。例えば、上のプログラムは次のようにしても同じように動きます。

 aaa();

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

関数の主な意義は繰り返し使えることにあります。プログラムを書くときの基本的なテクニックとして、「同じ処理を二度書かない」ことがあります。プログラムの複数箇所で同じことを行いたいとき、同じプログラムを2回書くよりは、その処理を担当する関数をひとつ作っておき、複数箇所からその関数を呼び出すほうが望ましいです。関数は色々と奥が深いのですが、このことは関数の基本的な利用法として覚えておくとよいでしょう。

引数のある関数

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」をつけて代入した変数は、ローカル変数になります。(文法上この説明はあまり正確でないのですが、それが分かる人は基礎なんか読んでいないでしょうから問題ありません。)

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

このソースの動作をみてみましょう。5行目の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を用いた変数宣言は代入を伴わずに行うこともできます。上のプログラムは次のようにもできます。

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

これは、関数aaaの中でvar a;の行により、変数aがローカル変数であると宣言しています。その後のa = 3;はローカル変数aに3を代入するという処理になります。

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

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

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

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

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

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が必要になります。(なお、他の方法でも文字列を数値に変換することはでき、parseIntを使う方法はちょっと違った特徴があるのですが、まあ今は気にしないでください。)

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

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

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

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

alertの行で、関数sumを呼び出してその戻り値を表示していることが分かると思います。なお、基礎第二回という概念を紹介しましたが、これらの例から分かるように関数呼び出しの関数名(引数)という形も式の一種であることが分かります。

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

これはreturn文です。return文は、与えられた値を関数の戻り値として返すものです。この場合、sumの戻り値は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は呼び出されなかったのです。ちなみにこの場合返り値がありませんが、その場合関数は何も返さないということになります(厳密には少し違いますが、ここでは解説しません)