関数を作ろう
関数とは
これまでのチュートリアルで「関数」というものが何回か登場しました。
たとえば小数点のついた数値を整数へ変換する関数parseInt()がありました。
関数とは、処理(足し算や文字列の結合、ifやfor文などこれまで学習してきたもの全て)をまとめて
名前を付けたものです。
一連の処理をまとめて利用しやすくすることで、同じコードを何度も書かなくて済みます。
関数はJavaScriptでさまざまなものがすでに用意されていますが、自分で作ることもできます。
まずは構文を見てみましょう
function 関数名(引数){
処理;
return 返り値;
}
実際に定義すると次のようになります。
function getFirstItem(list){
var firstItem = list[0];
return firstItem;
}
では順番に見ていきましょう
関数名
ここでは関数を使うときに書く名前、例えば「parseInt」みたいな名前ですね。
すでに存在する名前を使うことはできませんが、ある程度自由に付けることができます。
先頭は小文字の英字であること、キャメルケースで書くことが最低限の条件です。
キャメルケースとは、複数の単語から関数名が成る場合、2単語以降の先頭文字を大文字にするというルールです。
たとえば、「get user name」という単語を組み合わせてメソッドを作る場合は「getUserName」とします。
言語によっては「_」でつなぐルールもありますが、そちらはスネークケースと呼ばれています。「get_user_name」となります。
引数
関数を実行するとき、なにか値を渡して、その値に対して処理をしてほしいときがあります。parseIntであれば少数を含む数値が渡されますね。
「parseInt(1.2)」みたいな感じです。このとき渡す値を引数といいます。
引数は関数定義のときに定義した変数に格納されます。上で定義した関数で見ていきましょう。
関数を使うときは、関数名を書けばいいです。
getFirstItem([1,2,3,4,5]);
このとき、[1,2,3,4,5]が引数で、関数内ではlistにこの配列が格納されます。
引数は渡さなくてもいいですし、","で区切って複数渡すのもOKです.
//引数なし
function japaneseCode(){
return "ja";
}
var code = japaneseCode();
//引数が複数ある場合
function getItemByIndex(list, index){
if(index >= list.length){
return null;
} else {
return list[index];
}
}
var value = getItemByIndex([1,2,3,4,5]], 2);
返り値
関数は内部で処理をすると、処理結果を返却しなければなりません。
関数ないではさまざまな変数が操作されますが、どの値を返却するのかを決めるのがreturnです。
返却された値は次のように受け取ることができます。
var firstItem = getFirstItem([1,2,3,4,5]);
このようにすることでreturnによって返された値はfirstItemという変数に格納されます。
ただし、returnしたあとの処理は実行されないことにも注意しておきましょう。
スコープ
ちょっと難しい話題に入っていきます。
次のコードを見て実行してみてください。
var language = "ja";
function englishCode(){
var language = "en";
console.log(language);
return language;
}
var englishLanguageCode = englishCode();
console.log(language);
languageという変数が2回宣言されていますね。しかも別々の値が入っています。
実行された結果はどうでしょうか?
関数の中でlanguageには"en"が代入されましたが、関数の外で呼び出すと"ja"のままです。
この現象を紐解くにはスコープという概念を知る必要があります。
スコープとは、変数が存在していられる空間のことです。
関数定義内は関数独自のスコープ(空間)になるので、関数の外と中では存在している変数が異なるのです。
ただし、今回の場合は、languageが宣言されたスコープの中で関数も宣言されています。
スコープは関数宣言で区切られていても、内側からは外の世界が見えているのです。
しかし、外の世界から内側の世界は見れないため、関数宣言内で宣言された変数は外からみれません。
試しに次のコードはどうでしょうか?
var language = "ja";
function englishCode(){
language = "en";
console.log(language);
return language;
}
var englishLanguageCode = englishCode();
console.log(language);
varを取っただけですが、関数宣言の中からは外の世界が見えるのですでに存在しているlanguageを使いました。
もともと外の世界のものなので、書き換えると外の世界でも書き換わったままです。
最初のコードは、関数内でvarで宣言していたため、新しく同じ名前の変数を作ったのです。
関数内で定義したものは外へは出ていきません。
実は変数を宣言するときはvarは省略可能なのですが、このように思わぬ動作をしてしまうので、
新しく変数を宣言する場合は必ずvarを書きましょう。
なぜ関数を作るのか
そもそもなぜ関数を作るのでしょうか。
関数を作る理由は大きく二つあります。1つは長くなった関数を読みやすくするため、
もう1つは、複数回行う処理をまとめるためです。
一つ目の方から見ていきます。
哲学的な話になってきますが、関数には担うべき責務があります。例えばparseIntなら「整数に変換する」、
getUserNameなら「ユーザの名前を返却する」です。
メインの処理と言ってもいいでしょう。しかし、メインの処理のほかにもやらなくてはならないことがあったとします。
しかもその処理は結構複雑です。
var rate = 0.1;
function draw(){
var r;
r = mouseX * mouseX + mouseY * mouseY;
if (rate > 0){
r = r / rate;
} else {
r = r / 2;
}
ellipse(mouseX, mouseY, r, r);
}
この関数はProcessingでは描画を担う関数です。
しかし、その大半を描画ではなく、描く円の半径の計算に使っています。
こんな時は、半径を計算する関数を作って、描画関数の中をすっきりさせてあげましょう。
var rate = 0.1;
function draw(){
var r = radius();
ellipse(mouseX, mouseY, r, r);
}
function radius(){
var distanse;
distanse = mouseX * mouseX + mouseY * mouseY;
if (rate > 0){
return distanse / rate;
} else {
return r / 2;
}
}
どうでしょうか。描画処理と半径の計算処理を分けることができました。
分けることによって綺麗になっただけでなく、あとで修正するときにどこを直せばいいのかすぐに見つかるというメリットもあります。
次にもう一方の理由「複数回行う処理をまとめる」についてです。
さっそくコードを見ていきましょう
var age = 34;
if(age >= 50){
console.log("over 50!");
console.log("sorry goodby...");
} else if(age >= 40){
console.log("over 40!");
console.log("sorry goodby...");
} else if(age >= 30){
console.log("over 30!");
console.log("sorry goodby...");
} else if(age >= 20){
console.log("over 20!");
console.log("sorry goodby...");
} else{
console.log("under 19!");
}
間違えて「〇〇 over!」とするところを順番を間違えてしまいました。
こんなときは、初めから似たような処理を関数としてまとめておくと便利です。
var age = 34;
if(age >= 50){
ageMessage(50);
} else if(age >= 40){
ageMessage(40);
} else if(age >= 30){
ageMessage(30);
} else if(age >= 20){
ageMessage(20);
} else{
console.log("under 19!");
}
function ageMessage(age){
console.log(age + " over!");
console.log("sorry goodby...");
}
関数として似たような処理をまとめておくと、あとで変更が容易になります。
さらに、各if文での処理内容が2行から1行に減り、全体的にすっきりしました。
これらのメリットは、自分でいろいろなコードを書いているうちにありがたみが分かってくるものだと思っています。
なんかごちゃごちゃしてきたな、このコード何回も登場しているなと思ったら関数にしてみることを検討してください。
まとめ
- 関数名は先頭小文字英字のキャメルケースにしよう
- 引数はなくてもいいし、複数渡せる
- 返り値をreturn で書こう。ただし、returnしたらそのあとの処理は実行されない
- スコープを意識して、変数宣言にはvarを付けるようにしましょう
- 自分が見やすいように適度に関数に処理を分けていきましょう
後半はやや難しい内容だったと思います。
JavaScriptを使っているうちにだんだんと分かるようになってくるので、
今は関数をどうやって作るのか知っておくだけでいいでしょう。
チュートリアルはこれで完了です。最後に確認問題を用意しているので、どれだけ理解できたか確認してみてください。