JavaScriptの関数を使いこなすために知っておくべき基礎知識

2020年12月31日JavaScript

同じ言葉や数字が何度も出てくるとき、それを修正する必要がでたときに大変になります。
また、修正回数に伴ってミスも起きやすくなるという問題もでてきます。
それらの問題を解決するために、関数を使います。
具体的なJavaScriptの関数の使い方を学んでいきましょう。

JavaScriptの関数の使い方

function 関数名() {
処理内容
}

関数を使うときは、次のように書きます。

関数名();

たとえば、ある製品の紹介をしていて、その製品の詳細ページを文章のところどころに記載したいとしましょう。
その場合、次のように関数を作ることができます。

'use strict';

  function showProduct() {
    console.log('***************');
    console.log('*** Product ***');
    console.log('***************');
  }
  

そして、次のようにJavaScriptを記載すると関数を呼び出すことができます。

console.log('ここに文章');
  showProduct();
  console.log('ここに文章');
  showProduct();
  console.log('ここに文章');
  showProduct();

関数に引数を渡す

関数は引数を渡すことで、より柔軟な対応ができるようになります。

function 関数名(引数名) {
    処理内容;
    }

この引数を使うと次のようなことができるようになります。
処理内容がたとえば引数名を表示したいということであれば、テンプレートリテラルを使って表示してあげると、文字列の中の言葉を柔軟に変更することができます。

テンプレートリテラルを使っている例は以下の通りです。

console.log(`--- ${引数名} ---`);

具体例をみてみましょう。

'use strict';

    function showProduct(ProductName) {
      console.log('***************');
      console.log(`*** ${ProductName} ***`);
      console.log('***************');
    }
   
    console.log('ここに文章');
    showProduct('ProductA');
    console.log('ここに文章');
    showProduct('ProductB');
    console.log('ここに文章');
    showProduct('ProductC');

仮引数と実引数

仮引数は、関数を定義するときに名付ける引数で、値を仮に置いているので、仮引数と呼びます。
実際に関数を呼び出すときに使われる引数は、実引数と呼びます。ただし、実際にはどちらも引数と呼ばれている場合が多いです。

function 関数名(仮引数) {
  処理内容;
}
  関数名(実引数);

引数の数が決まっていないとき(argumentsとレストパラメータ)

arguments は関数コンテキストで自動的に生成されます。
arguments はオブジェクトで、呼び出し時に渡された実引数が渡ってきます。

つまり引数の役割を果たすことができます。

argumentsの利用例をみてみましょう。

//arguments keywordと通常の関数
const add = function (a, b) {
  console.log(arguments); //Argumentsの中身がみれる
  return a + b;
};
add(3, 4);//仮引数と同じ数だけ渡す
add(3, 4, 5, 6);//仮引数以上の数を渡すこともできる

//アロー関数とarguments
var add = (a, b) => {
  console.log(arguments); //Arguments is not definedが返される
  return a + b;
};

このように、argumentsキーワードは、通常の関数(関数宣言と関数式)で扱えますが、アロー関数では扱えません。
そのため、アロー関数でarugumentsをコンソールに出力するとArguments is not definedが返されます。

通常の関数の仮引数以上に実引数を渡すことができます。
それらには、仮引数で名前は与えられていない状態ですが、argumentsの中身をみるとしっかりと存在しています。

ループ処理のときなどにargumentsは便利です。
argumentsは渡される引数が決まっていない場合に使うケースがあります。
ただし、レストパラメーターを仮引数に設定できるため、最近では利用されません。
レストパラメーターについてはJavaScriptJavaScriptのレスト構文の使い方を参照してみてください。

//arguments
function fn1() {
console.log(arguments);
}

//レストパラメータ
function fn2(...args) {
//レストパラメータで引数を格納できる
console.log(args);
}

fn1(1, 2, 3, 4); //Arguments(4) [1, 2, 3, 4, callee: ƒ, Symbol(Symbol.iterator): ƒ]
fn2(1, 2, 3, 4); //(4) [1, 2, 3, 4]

引数を渡さないときのデフォルト値の設定方法

引数に何も渡さないときのデフォルトとしての値を設定することができます。
その設定方法は次の通りです。

function 関数名(引数 = デフォルト値) {
処理内容:
}

たとえば、次のデフォルト値をProductDとしたい場合、次のように書きます。

関数のデフォルト値設定:具体例1

'use strict';

  function showProduct(ProductName = 'ProductD') {
    console.log('***************');
    console.log(`*** ${ProductName} ***`);
    console.log('***************');
  }
 
  console.log('ここに文章');
  showProduct('ProductA');
  console.log('ここに文章');
  showProduct('ProductB');
  console.log('ここに文章');
  showProduct('ProductC');

関数のデフォルト値設定:具体例2

また、デフォルト値には、100 * 1.1などの計算式を入れることもできます。

さらに、下の例のように先に仮引数として登録した引数をかけ合わせて使うことも可能です。
後に設定する引数は使えないので、順番を入れ替えましょう。

下のように最初や途中の実引数を渡すのをスキップして値を渡したいときは、undefinedを使います。

//関数の仮引数にデフォルト値を設定する
//booking function

const bookings = [];

//ES6からのデフォルト値の設定方法
const createBooking = function (
  ticketNum,
  numCustomers = 1,
  // price = 100 * 1.1
  price = 100 * numCustomers * 1.1
) {
  //ES5までのデフォルト値の設定方法
  // numCustomers = numCustomers || 1;
  // price = price || 100;

  const booking = {
    ticketNum,
    numCustomers,
    price,
  };
  console.log(booking);
  bookings.push(booking);
};

createBooking('bb333');
//デフォルト値がない場合{ticketNum: "bb333", numCustomers: undefined, price: undefined}
//デフォルト値がある場合{ticketNum: "bb333", numCustomers: 1, price: 110}

createBooking('aa444', 2, 200);
//{ticketNum: "bb333", numCustomers: 2, price: 200}

//最初や途中の引数をスキップして値を渡したいとき
createBooking('cc555', undefined, 2000);//{ticketNum: "cc555", numCustomers: 1, price: 2000}

またnullを渡すと、そのままnullが返されますが、undefinedを渡すと、デフォルト値が返されます。

returnの使い方

たとえば下の例の場合、それぞれのsumを足した合計を知りたい場合に面倒になります。

'use strict';
function sum(a, b, c, d) {
  console.log(a + b + c + d);
}

sum(1, 2, 3, 4);
sum(2, 4, 6, 8);

上のケースは、returnを使うと返す値を書き換えることができます。
関数で値を返すと、他のところで計算に使えるので便利になります。

'use strict';
function sum(a, b, c, d) {
  //console.log(a + b + c + d);
  return a + b + c + d;
}

sum(1, 2, 3, 4);
sum(2, 4, 6, 8);

const total = sum(1, 2, 3, 4) + sum(2, 4, 6, 8);

上の場合、sumの実引数がreturnで値が返されてそれぞれ、10と20が返り、それらをtotalで足し算するので、結果は30となります。

一方でreturnで値として書き換える文がないと、たとえばconst total = sum(1, 2, 3, 4) + sum(2, 4, 6, 8);としても、10と20が表示されてしまいます。

注意点としては、returnを書くとその時点で値が返されてそれ以降に書いた処理内容は実行されません。
よって、returnは関数の処理内容の最後に書くようにしましょう。

関数宣言と関数式

関数には、関数宣言でかく方法と、関数式でかく方法があります。


//関数宣言は次のような書き方です。
function 関数名(仮引数) {
  処理内容;
  return 返り値;
}

//関数式は、次のような書き方です。
const 定数名 = function(仮引数) {
  処理内容;
  return 返り値;
};

関数宣言と関数式の違い

関数宣言と関数式の違いは、関数宣言の方は関数名があるのに対し、関数式には関数名がなく定数に代入される点です。
その違いが呼び出し処理のときにも表れます。
関数宣言は、関数名(…);という形ですが、関数式は定数名(…);という形で呼び出します。
また、関数宣言の最後にセミコロンは不要ですが、関数式は定数の定義なので、セミコロンが必要になります。

関数式は、関数名がないので、無名関数とよばれることもあります。
関数式を使うときは、最後のセミコロンを忘れがちなので注意が必要です。

また関数式は、上のように定数で宣言しているので、関数の実行文より前に書く必要があります。
一方で無名関数は関数の実行文より下に書いても問題ありません。

アロー関数

関数はよく使うので、省略した書き方が存在します。
アロー関数は、無名関数を記述しやすくした省略記法です。
次の関数式をアロー関数にしてみましょう。


  const 定数名 = function (仮引数) {
    return 処理内容;
  }

アロー関数にするには次の手順の通りです。

  • functionをとる
  • 仮引数と処理内容の間に=>をいれる
  • 処理内容が一行の場合、仮引数と処理内容の間の{}をとる
  • {}を省略した場合、returnをとる
  • 引数が一つの場合、引数の()をとる

const 定数名 = 仮引数 => 処理内容;

下のコメント部分が関数式で書いた方法で、その下が、アロー関数で書いた式です。


  //省略なしの関数式
  const triple = function(num) {
    return num * 3;
  }
  //アロー関数で省略した場合
  const triple = num => num * 3;

引数が一つ以外の場合、ゼロの場合も含めて引数の()は省略できません。また、{}を記載する場合は、returnは省略できません。

アロー関数と無形関数の違い

アロー関数は基本的には無形関数の簡略記法ですが、次のように多くの違いがあるので注意しましょう。

無名関数 アロー関数
this ×
arguments ×
new ×
prototype ×

アロー関数とthisについてはJavaScriptのthisキーワードについてを参照してみてください。

関数は実行可能なオブジェクト

関数は実行可能なオブジェクトです。
JavaScript での関数は、オブジェクトです。他のオブジェクトと異なる点は実行可能という点だけです。

データ型でも、プリミティブ型ではないものをオブジェクトといいますが、関数もまたオブジェクトとなります。

function hello() {
console.log("hello");
}
hello.a = "a";
hello.method = function () {
console.log("method");
};

hello(); //hello
hello.method(); //method
console.log(hello.a); //a

このように関数宣言で宣言した関数に対してメソッドやプロパティを追加することができます。つまり、関数はオブジェクトということです。

コールバック関数

関数は実行可能なオブジェクトです。オブジェクトなので、他の関数に引数として渡すことができます。
引数に渡す関数のことを、コールバック関数といいます。
コールバック関数を理解するために、通常の関数の例をみてみましょう。

function fn(hello) {
  console.log(hello);
}
fn("こんにちは");//こんにちは

コンソールの中のhelloは、引数から渡ってきた値です。
関数の引数には関数を取ることができます。

//コールバック関数を受け取る関数
function fn(hello) { //helloには関数hiが渡される
  console.log(hello());//hello()はhi()になる
}

//引数に渡す関数(=コールバック関数)
function hi() {
  // console.log('hi');
  return "こんにちは";
}

fn(hi); //こんにちは

hiという関数を設定し、戻り値を設定します。
hiという関数をfnという関数に渡します。
コンソールの中のhelloは、引数から渡ってきた値でかつ、関数なので、実行の意味の()をつけることで実行できます。
このように関数はオブジェクトのため、引数として渡すことも可能となります。
そして、引数に渡す関数のことを、コールバック関数といいます。

コールバック関数に引数を加える

コールバック関数も関数のため、引数をとることも可能です。

//コールバック関数を受け取る関数
function fn(callback, firstname) {
  console.log("hi " + callback(firstname));
  // callback(firstname)はつまり、hello('taro);とイコール
}

//引数に渡す関数(=コールバック関数)
const hello = function (name) {
  return "yamada " + name;
};

// 関数fnの第一引数は関数、第二引数に文字列を渡している
fn(hello, "taro");
// hi yamada taro

callbackにhelloが渡され、firstnameにtaroが渡されます。
つまり、callback(firstname)は、hello('taro’)となります。
そのため、nameはtaroであり、hi yamada taroが出力されます。

JavaScriptでは引数の数を合わせる必要はないので、呼び出す関数に実引数がなくても問題ありません。
渡す方の関数は引数に()をつけることで呼び出すことができます。

コールバック関数と無名関数

//コールバック関数を受け取る関数
function fn(callback, firstname) {
  console.log("hi " + callback(firstname));
}

//引数に渡す関数(=コールバック関数)
// 関数fnの第一引数は無名関数、第二引数に文字列を渡している
fn(function (name) {
  return "yamada " + name;
}, "taro");
// hi yamada taro

関数fnの第一引数は無名関数、第二引数に文字列を指定しています。その2つが、fnの引数に渡され、コンソールで実行されます。
無名関数のnameはfnに渡された後、
callback(firstname)のため、
nameはfirstnameとなり、
firstnameはtaroが渡されるので、nameはtaroになります。
また、上の例のように無名関数もコールバック関数になります。

setTimeout()

setTimeout()は JavaScript エンジンによって提供される WebAPI のひとつです。第一引数にコールバック関数をとります。
function hello() {
console.log(“hello");
}
setTimeout(hello, 1000);
コールバック関数によって処理を切り分けることで、汎用的な部品を作ることができます。
このようにコールバック関数は再利用性を高めることができます。
setInterval()とsetTimeout()を使い方については、JavaScriptのsetInterval()とsetTimeout()を使い方を参考にしてみてください。

コールバック関数の使用例

次のように値とコールバック関数を渡すことで新しい処理をした結果をつくることが可能になります。


function calculation(x, y, calc) {
  const result = calc(x, y);
  console.log(result);
}

function multiply(x, y) {
  return x * y;
}

function divide(x, y) {
  return x / y;
}

function plus(x, y) {
  return x + y;
}

calculation(2, 10, multiply); //20
calculation(2, 10, divide); //0.2
calculation(2, 10, plus); //12

一番下に記載しているcalculation関数の中に指定された値が一番上のcalculation関数のそれぞれの引数に渡されます。
xには2を
yには10を
そしてcalcには関数を渡しています。
calcにはさらにx,yの引数があるので、その指定された関数の引数にxとyの値を渡して計算しています。

このようにコールバック関数をうまく使うことで、同じ関数でも処理結果を変わる汎用性の高い部品が作成できます。