Tips

JavaScriptにおける関数の種類と使い方を解説【引数、戻り値、デフォルト引数でNaNになる理由など】

  • このエントリーをはてなブックマークに追加

「ちゃんと調べて書いているはずなのに実行されない」
「関数は実行されるがエラーを起こしやすく、何が原因かが毎回分からない」
「基本的にJavaScriptはググってコピペしている」

JavaScript(jQueryも)に対して、上記のように感じられている方は多いのではないでしょうか。

今回はJavaScriptの関数について、基本的な使い方と注意すべきポイントを解説していきます。

学習教材やYoutube動画では解説されていない点も多くありますので、ぜひザっと目を通してみてください。

また動画も用意しているのでお好みでご確認ください。

JavaScriptにおける基本的な関数の書き方

基本的な書き方は以下の通りです。

function myFunctionB(){
  console.log("hello");
};

functionという文法を使って「myFunctionB」という名前の関数を作っています。

関数の名前は好きな名前にすることができますが、「何をしているか」が分かる名前にしておくと後から見返したときに分かりやすいです。

また上記の内容では関数は実行されません。

あくまで用意しているだけだからです。

用意した関数を実際に実行するには実行文を別で書く必要があります。

myFunctionB();

自分で作った関数の名前と「( )」を書くことで実行されます。

全体としては以下のようになります。

function myFunctionB(){
  console.log("hello");
};

myFunctionB(); //helloが出力

JavaScriptによる関数は上記の書き方だけではなく色んなスタイルがありますが、今回は基本的な書き方に重点を置いて進めていきます。

ちなみにですが「なぜ関数なんてものが必要なんだろうか?」と思われる初学者の方がいるかもしれません。

上記のような簡単なコードだと関数の書き方でなくても問題ないでしょう。

例えば以下のようなコードがあったとします。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="./style.css" />
    <script src="./script.js" defer></script>
  </head>
  <body>
    <ul id="result"></ul>
  </body>
</html>
const result = document.querySelector("#result");

for (let i = 0; i < 10; i++) {
  let el = `<li>${i}</li>`;
  result.insertAdjacentHTML("beforebegin", el);
}

繰り返し構文で数字をカウントして画面に表示するプログラムです。

例えばこの繰り返しが何回も必要になった場合はコードをコピペして以下のようにすることになります。

const result = document.querySelector("#result");
// 繰り返しを3回分やりたいとき
for (let i = 0; i < 10; i++) {
  let el = `<li>${i}</li>`;
  result.insertAdjacentHTML("beforebegin", el);
}
for (let i = 0; i < 10; i++) {
  let el = `<li>${i}</li>`;
  result.insertAdjacentHTML("beforebegin", el);
}
for (let i = 0; i < 10; i++) {
  let el = `<li>${i}</li>`;
  result.insertAdjacentHTML("beforebegin", el);
}

もちろん上記のコードでも問題ないですが、パッと見た感じ面倒というか冗長に見えますよね。

関数を使うと同じ処理を以下のようにすることができます。

const result = document.querySelector("#result");
// 繰り返し処理を関数として用意して、実行だけを3回書く
function numCount() {
  for (let i = 0; i < 10; i++) {
    let el = `<li>${i}</li>`;
    result.insertAdjacentHTML("beforebegin", el);
  }
}
numCount();
numCount();
numCount();

冒頭で「関数は書いただけでは実行されません」と説明しました。

その特徴を言い換えると「関数部分は無視されるからテンプレートのようなものとして用意しておき、後は必要な実行コードの1行だけを書く」とすることができるのです。

初学者の方も学習や個人開発などで「これは関数にした方が便利そう」という部分を見つけてみましょう。

戻り値(return)が何をしているのか

戻り値もしくは返り値という言葉を聞いたことがあるかもしれません。

単語として中々とっつきにくいので、実際に何をするためのものかが分かりにくいですよね。

僕は関数の説明をするときには「数学」に例えることが多いです。

必ずしも数学と同じ考え方が適用できるわけではありませんが、「ざっくり」の意味を理解するには非常に良い例だからです。

数学のー次関数を覚えているでしょうか、

「y=2x」のようなものです。

ー次関数でいう「y」が戻り値と同じようなものです。

何かの計算や処理をした計算結果を最終的に返すのが関数の基本的な構造なんです。

JavaScriptにおける戻り値は「return」を使って表現します。

function myFunctionB(){
  console.log("hello");
  return 100;
};

「return」を書く場所に注意です。

先ほど戻り値のことを「計算結果」と表現しました。

関数において基本的に戻り値の後に続けてコードを記載しても実行されません。

function myFunctionA(){
  return 100;
  console.log("hello");
};

上記の場合、「return 100」の部分は実行されますが、「console.log」については実行されません。

JavaScriptで開発を進めていくときに、デバックなどで「cosole.log」を色んな場所で使いますが関数のなかではreturnの位置に注意しておくと良いでしょう。

また戻り値を取得したいときにも書き方に注意です。

以下のような書き方をしても戻り値を取得することはできません。

function myFunctionB(){
  console.log("hello");
  return 100;
};
// ここを追加
console.log(myFunctionB);

コンソールには上図のような形で表示されていてエラーでは無いですが期待した「100」ではありません。

こちらも冒頭で説明したことに繋がるのですが、戻り値は関数が実行されないと取得できません。

関数が実行されていないのであれば「計算結果もない」となるためです。

そのため以下のような書き方をすることで戻り値を取得することができます。

function myFunctionB(){
  console.log("hello");
  return 100;
};
// ここを変更
console.log(myFunctionB());

戻り値を変数や定数に格納したい場合も同じで関数を実行することが必要です。

見ただけではイメージしづらいと思いますので、ぜひお手元で違いを確かめてみてください。

引数について

続いて「引数」についてです。

先ほどから数学に例えていますが、「y=2x」というー次関数があった場合に引数は「x」と同じようなものと思って頂ければ良いです。

function myFunctionA(a){
  let test = a + 1;
  return test;
};

引数は関数の名前の横で「( )」の中に書きます。

引数の名前は自由に決めることができますが、こちらも後で見返したときに分かるような名前にしておくと良いでしょう。

引数を使う場合の実行は以下のようにします。

myFunctionA(100);

「( )」のなかに当てはめたい値を書きます。

全体としては以下の通りです。

function myFunctionA(a){
  let test = a + 1;
  return test;
};
const result = myFunctionA(100);
console.log(result); //101が出力

関数において引数は必須ではないですが、引数があった方がワンパターンにならず柔軟な関数にすることができます。

「似たような関数を何個も作ってるなぁ」と感じたときは引数を指定することで効率化できることがああります。

また引数は1個だけじゃなくても大丈夫です。

function myFunctionA(a,b){
  let test = a + b;
  return test;
};
const result = myFunctionA(1,2);
console.log(result); //3が出力

さらに引数には「初期値」を設定することもできます。

「実行するたびに引数を指定するのは手間だけど、引数を使いたいけど特定の値に偏りがち」なんてときに便利です。

また状況によりますが引数に初期値があることで、「引数を指定しそびれてもエラーにならない」と言う考え方もできます。

function calFunction(price, tax = 0.1){
  const result = price + price * tax;
  return result;
};
const calFunction_result = calFunction(100);
console.log(calFunction_result); //110が出力

上記は消費税10%を含めた価格計算を行っています。

消費税10%というのは毎回変わらないはずなので、「tax」という名前の引数に「0.1」を事前に設定しています。

「tax」のように初期値を設定した引数については、実行する際に書かなくて大丈夫です。

上記では「calFunction(100)」というように、「price」という引数のみに値をセットしています。

ちなみに初期値を上書きすることもできます。

function calFunction(price, tax = 0.1){
  const result = price + price * tax;
  return result;
};
const calFunction_result = calFunction(100,0.08);
console.log(calFunction_result); //108が出力

上記では消費税が軽減税率の「0.08」になる場合を想定した価格計算を行っています。

あえて初期値を変更したいときには、実行する際に値をセットすれば上書きされます。

デフォルト引数の罠に注意!

引数に初期値を入れることは大変便利ですが、特定のケースでは注意が必要です。

例えば以下のコードがあります。

const minusNum = (a = 10, b) => {
  console.log(a - b);
};
minusNum(5);

第一引数に初期値を設定して、実行時に第二引数だけ値を入れたとします。

上記のコードだと10-5=5を期待するところですがうまくいきません。

NaNというのはエラーではないのですが「数字ではない」という意味です。

なぜNaNになるかというと第一引数にデフォルト引数を指定した関数だからです。

2個以上の引数は実行するときに第一引数、第二引数。。。と順番に値を入れることになります。

上記のコードで第二引数にだけ5を書いたとしても、結果的には第一引数の方に5が代入されて第二引数には何も値が無い状態になるのです。

そのため10-xで計算ができずにNaNが表示されたわけです。

第一引数にデフォルト引数を指定した場合、実行するときは第一引数にundefinedを代入しましょう。

const minusNum = (a = 10, b) => {
  console.log(a - b);
};
// ここを修正
minusNum(undefined, 5);

これで第一引数には何も指定していませんが初期値の10が代入されて、第二引数は自分で書いた5が代入されて正常に計算できました。

「デフォルト引数だから書かなくて良い」という理解だとハマるので注意しましょう。

戻り値(return)は2回使うこともできる?!

関数は引数と戻り値を意識しておくだけで大体のことは理解できます。

少し応用して以下のような内容も作れます。

function myFunctionC(a,b){
  if(a >= 100){
    return a;
  }
  return b;
};
const myFunctionC_result = myFunctionC(120,0);
console.log(myFunctionC_result);  //120が出力

戻り値は2回使うこともできることを例にしてみました。

また関数のなかで条件分岐も使っています。

上記では引数aにセットした値によって戻り値が変わる様子を表しています。

function myFunctionC(a,b){
  if(a >= 100){
    return a;
  }
  return b;
};
const myFunctionC_result = myFunctionC(90,0);
console.log(myFunctionC_result);  //90が出力

「引数」「戻り値」など単語だけ見ると、「難しそうだな」と思われるかもしれませんが基本的な考え方は数学に似ているので覚えてしまえば何てことないのです。

引数の個数は何個でも良い

引数について便利な書き方を紹介します。

これまでの説明では引数というのは、「何個セットするか」が決まっている前提のお話でした。

しかし実際には引数の個数が決まっていないケースもありますよね。

そんなときは以下のように書くことで引数の個数を変幻自在にすることが可能です。

function calcSum(...prices){
  let result = 0;
  for(const value of prices){
    result += value;
  }
  return result;
};
const calcSum_result = calcSum(100,200);
console.log(calcSum_result); //300が出力

上記は引数の合計を算出する関数なのですが、引数の部分が「…」となっているのがポイントです。

このように書くことで「何個でもセットしてOK」となるのです。

ちなみに同じことは以下のようにも実現できます。

function calcSum(price1, price2){
  let result = 0;
  result = price1 + price2;
  return result;
};
const calcSum_result = calcSum(100,200);
console.log(calcSum_result); //300が出力

同じ結果になりますが、事前に引数の個数を分かっておく必要がありますし、for文のような繰り返しが使いにくくなってしまいます。

さらに以下のように引数の個数を変化させると正常に動作しなくなります。

function calcSum(price1, price2){
  let result = 0;
  result = price1 + price2;
  return result;
};
const calcSum_result = calcSum(100,200,300);
console.log(calcSum_result); //600が出力されない

引数の個数が変化しても対応できるようにするには「…」を使うことをおススメします。

最後にそれぞれ見比べてみましょう。

//引数の個数を限定してしまっている例
function calcSum(price1, price2){
  let result = 0;
  result = price1 + price2;
  return result;
};
const calcSum_result = calcSum(100,200,300);
console.log(calcSum_result); //600が出力されない

//引数の個数を自由にしている例
function calcSum(...prices){
  let result = 0;
  for(const value of prices){
    result += value;
  }
  return result;
};
const calcSum_result = calcSum(100,200,300);
console.log(calcSum_result); //600が出力

「…prices」のような書き方はJavaScriptではスプレッド構文という特殊な文法から来ています。

興味がある方はスプレッド構文についても解説したのでご覧ください。

また今回参考にした本はこちらになります。

良ければどうぞ。

  • このエントリーをはてなブックマークに追加