関数宣言と関数式の違いとは?[JavaScript].NET TIPS

JavaScriptで関数を定義するには、関数宣言による方法と関数式による方法がある。本稿ではこれらの違いについて説明する。

» 2016年05月18日 05時00分 公開
[山本康彦BluewaterSoft/Microsoft MVP for Windows Development]
.NET TIPS
Insider.NET

 

「.NET TIPS」のインデックス

連載目次

 JavaScriptの関数には、何通りかの書き方がある。どのような違いがあるのだろうか? 本稿では、その中から関数宣言と関数式の違いについて解説する。

関数宣言(function文)

 これは、関数を宣言する構文(function文、MSDNではfunctionステートメント)を使う方法である。次のコードのような使い方をする。

function func1(n) {
  return "これはfunc1です。値は" + n;
}
var result = func1(1);
var name = func1.name;
alert(name + ": " + result);
// 出力⇒func1: これはfunc1です。値は1

関数宣言(function文)を使うコードの例(JavaScript)

 JavaScriptでは、関数もオブジェクトである(Functionオブジェクト)。オブジェクトであるから、プロパティやメソッドを持っている。上のコードでは、関数の名前を表すnameプロパティを使っている。

関数式(function演算子)

 これは、function演算子を使う方法である(MSDNでは関数宣言と名称の区別はしていないようだ)。次のコードのような使い方をする。

// 無名関数
{
  var func2 = function (n) {
    return "これはfunc2です。値は" + n;
  }
  var result = func2(2);
  var name = func2.name;
  if (name === "")
    name = "(空文字)";
  alert(name + ": " + result);
  // 出力⇒(空文字): これはfunc2です。値は2
}

// 名前付き関数
{
  var func3 = function function3 (n) {
    return "これはfunc3です。値は" + n;
  }
  var result = func3(3);
  var name = func3.name;
  alert(name + ": " + result);
  // 出力⇒function3: これはfunc3です。値は3
}

関数式(function演算子)を使うコードの例(JavaScript)
関数式では、関数名を省略できる。関数式はそのままでは呼び出せず、このコードのように変数に代入するなどしてから呼び出す。そのため、関数式に関数名を指定するのはあまり意味がない。関数名が必要だと思えるのは、再帰関数を書くときくらいではないだろうか(無名関数でも再帰は書けるが、少しだけ分かりにくい)。
関数名を省略した場合、生成されたFunctionオブジェクトのnameプロパティは空文字になる。

 なお、ECMAScript 2015(第6版)からは、次のコードに示すようなアロー関数式も追加された。Edgeブラウザや最近のFirefox/Chromeブラウザなどで対応が始まっている。

// ブロック文体(block body)…値を返すにはreturn文が必要
{
  var func4 = (n) => {
    return "これはfunc4です。値は" + n;
  };
  var result = func4(4);
  var name = func4.name;
  alert(name + ": " + result);
  // 出力⇒func4: これはfunc4です。値は4
}

// 簡潔文体(concise body)…暗黙的に値が返される
{
  var func5 = n => "これはfunc5です。値は" + n;
  var result = func5(5);
  var name = func5.name;
  alert(name + ": " + result);
  // 出力⇒func5: これはfunc5です。値は5
}

アロー関数式を使うコードの例(JavaScript)
C#のラムダ式とよく似ている。引数が1個のときはその左右のかっこを省略できるのも同じだ(func5関数の定義の例)。
なお、Windows 10のEdgeブラウザでは、コメントで示したようにnameプロパティが設定された。Firefox/Chromeブラウザでは、nameプロパティは空文字になった。

関数宣言と関数式の違いとは?

 端的に言うと、Functionオブジェクトの生成されるタイミングが違う。他にも細かい相違はたくさんあるが、それらについてはMDNの「関数と関数スコープ」などを参照していただきたい。

 関数宣言は、宣言を含むスコープが実行されるまでにFunctionオブジェクトが生成される。対して関数式は、その式が実行されるときにFunctionオブジェクトが生成されるのだ。

 そのため、Functionオブジェクトを生成するのに時間がかかる巨大で複雑な関数の場合には、関数宣言と関数式でパフォーマンスに違いが出てくるはずである(どちらがよいとは一概にはいえない)。通常は、書きやすい方を使えばよいだろう。

 コーディングの実用面では、関数宣言はそれより手前でも呼び出せるが、関数式では文法エラーになる(次のコード)。

// 関数宣言は、その手前でも呼び出せる
{
  var result = func1(1);
  var name = func1.name;
  alert(name + ": " + result);
  // 出力⇒func1: これはfunc1です。値は1

  function func1(n) {
    return "これはfunc1です。値は" + n;
  }
}

// 関数式は、その手前では呼び出せない
{
  var result_NG = func2(2); // × 文法エラー

  var func2 = function (n) {
    return "これはfunc2です。値は" + n;
  }
}

関数宣言と関数式の違いの例(JavaScript)
関数宣言: func1関数のFunctionオブジェクトは、遅くともそのスコープの実行が始まるまでに生成される。そのため、関数宣言の手前でも呼び出せる。
関数式: 変数func2が参照するFunctionオブジェクトが生成されるのは「var func2 =……」の行が実行されたとき。従って、それよりも前ではFunctionオブジェクトが存在しない(strictモードでは変数func2も存在しない)ので、呼び出せない。

まとめ

 関数宣言と関数式では、Functionオブジェクトの生成されるタイミングが異なる。それによるパフォーマンスの違いを通常は気にする必要はないが、覚えておいた方がよいだろう。普段の実用面では、関数の定義よりも手前で呼び出せるかどうかという違いになる。

「.NET TIPS」のインデックス

.NET TIPS

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。