一般的に言うと、関数とは外部 (再帰の場合は内部) から 呼ばれる ことのできる「サブプログラム」です。プログラムそのもののように、関数は関数本体と呼ばれる連続した文で構成されます。値を関数に 渡す 事ができ、関数は値を返す事ができます。

JavaScript において、関数は第一級オブジェクトです。すなわち、関数はオブジェクトであり、他のあらゆるオブジェクトと同じように操作したり渡したりする事ができます。具体的には、関数は Function オブジェクトです。

より詳細な例や解説については、JavaScript の関数のガイドを参照してください。

一般

JavaScript における全ての関数は、実際には Function オブジェクトです。Function オブジェクトのプロパティとメソッドについての情報は Function をご覧ください。

初期値以外の値を返すためには、返す値を指定する return 文が関数内になくてはなりません。return 文を持たない関数は初期値を返します。new キーワードとともに constructor が呼び出された場合、その this パラメータが初期値となります。それ以外の全ての関数がデフォルトで返す値は undefined です。

関数の仮引数 (パラメータ) には、関数呼び出しにおいて実引数 (アーギュメント) が渡されます。実引数は、関数に「値渡し」されます: 関数の中で引数の値を変更しても、その変更はグローバルスコープもしくは呼び出し元の関数内には反映されません。オブジェクト参照も「値」ですが、こちらは特別です: 参照されているオブジェクトのプロパティを関数の中で変更すると、次の例にあるように、その変更を関数の外部から見ることができます:

 /* 関数 'myFunc' を宣言 */
 function myFunc(theObject) {
   theObject.brand = "Toyota";
 }
 
 /*
  * 変数 'mycar' を宣言
  * 新しいオブジェクトの生成と初期化
  * 'mycar' への参照をオブジェクトに代入
  */
 var mycar = {
   brand: "Honda",
   model: "Accord",
   year: 1998
 };

 /* 'Honda' を表示 */
 window.alert(mycar.brand);

 /* オブジェクト参照を関数に渡す */
 myFunc(mycar);

 /*
  * オブジェクトの 'brand' プロパティの値は関数によって変更されたので
  * 'Toyota' と表示される
  */
 window.alert(mycar.brand);

this キーワードは現在実行中の関数を参照しません。よって、関数内部であっても、名前によって Function オブジェクトを参照しなければなりません。

関数を定義する

関数を定義するのにはいくつかの方法があります。

関数宣言 (function 文)

関数を宣言するための特殊な構文があります。(詳細は function 文を参照)

function name([param[, param[, ... param]]]) {
   statements
}
name
関数名。
param
関数に渡される引数の名前。関数は最大 255 個の引数を持つことができます。
statements
関数の本体を構成する文。

関数式 (function 演算子)

関数式は、関数宣言と似ており、同じ構文を持っています (詳細は function 演算子を参照)。関数式はより大きな式の一部になることもあります。「名前付き」の関数式を定義することもできます(例えばその名前はコールスタック内で使われるかもしれません)し、「無名の」関数式を定義することもできます。関数式はスコープの開始時に「巻き上げ」られないので、コード内でそれらが登場するより前に使用することはできません。

function [name]([param] [, param] [..., param]) {
   statements
}
name
関数名。省略する事ができ、その場合関数は無名関数と見なされます。
param
関数に渡される引数の名前。関数は最大 255 個の引数を持つことができます。
statements
関数の本体を構成する文。

以下は無名の関数式(名前が使われていない)の例です。

var myFunction = function() {
    statements
}

名前付きの関数式を作るため、定義の中で名前を提供することも可能です。

var myFunction = function namedFunction(){
    statements
}

名前付きの関数式を作ることのメリットの 1 つは、エラーに遭遇したとき、スタックトレースがその関数の名前を含めるため、エラーの発生源をより容易に特定できるということです。

ここまで見てきたように、どちらの例も function キーワードから開始されていません。function から開始せずに関数を含んでいる文が関数式です。

関数を一度だけ使うときの一般的なパターンが即時関数(IIFE: Immediately Invokable Function Expressions) です。

(function() {
    statements
})();

即時関数は、関数を宣言した直後に実行する関数式です。

ジェネレータ関数宣言(function* 文)

ジェネレータ関数の宣言のための特別な構文です(詳細は function* 文 を参照してください)。

function* name([param[, param[, ... param]]]) {statements }
name
関数名。
param
関数に渡される引数の名前。関数は最大 255 個の引数を持つことができます。
statements
関数の本体を構成する文。

ジェネレータ関数式(function* 演算子)

ジェネレータ関数式は、ジェネレータ関数宣言と似ており、同じ構文を持っています (詳細は function* 演算子 を参照してください)。

function* [name]([param[, param[, ... param]]]) {statements }
name
関数名。省略する事ができ、その場合関数は無名関数と見なされます。
param
関数に渡される引数の名前。関数は最大 255 個の引数を持つことができます。
statements
関数の本体を構成する文。

アロー関数式 (=>)

アロー関数式は短縮構文を持ち、また関数の this 値を語彙的に束縛します (詳細はアロー関数を参照):

([param] [, param]) => { statements } param => expression
param
引数の名前。引数が 0個の場合は () で示すことが必要です。引数が 1個の場合のみ、丸括弧は必須ではありません。(例えば foo => 1)
statements または expression
複数の文は中括弧で括らなければなりません。単一の式では、中括弧は必須ではありません。式は、関数の暗黙的な戻り値でもあります。

Function コンストラクタ

注記: Function コンストラクタによる関数の生成は推奨されません。これは、文字列として関数本体が必要で、JS エンジンによる最適化を妨げたり、他の問題を引き起こしたりする場合があるためです。

他の全てのオブジェクトと同じように、new 演算子を使って Function オブジェクトを作成する事ができます。

new Function (arg1, arg2, ... argN, functionBody)
arg1, arg2, ... argN
関数で仮引数名として使われる、0 個以上の名前。それぞれが、妥当な JavaScript 識別子に相当する文字列、もしくはそういった文字列のカンマで分割されたリストでなくてはなりません。例えば "x" 、"theValue"、もしくは "a,b" などです。
functionBody
関数定義を構成する JavaScript 文を含む文字列。

Function コンストラクタを関数として (new 演算子を使わずに) 呼び出しても、コンストラクタとして呼び出すのと同じ効果があります。

GeneratorFunction コンストラクタ

注記: GeneratorFunction はグローバルオブジェクトではありませんが、ジェネレータ関数のインスタンスから得ることができます(詳細は GeneratorFunction を参照してください)。

注記: GeneratorFunction コンストラクタによる関数の生成は推奨されません。これは、文字列として関数本体が必要で、JS エンジンによる最適化を妨げたり、他の問題を引き起こしたりする場合があるためです。

他の全てのオブジェクトと同じように、new 演算子を使って GeneratorFunction オブジェクトを作成する事ができます。

new GeneratorFunction (arg1arg2, ... argNfunctionBody)
arg1, arg2, ... argN
関数で仮引数名として使われる、0 個以上の名前。それぞれが、妥当な JavaScript 識別子に相当する文字列、もしくはそういった文字列のカンマで分割されたリストでなくてはなりません。例えば "x" 、"theValue"、もしくは "a,b" などです。
functionBody
関数定義を構成する JavaScript 文を含む文字列。

Function コンストラクタを関数として (new 演算子を使わずに) 呼び出しても、コンストラクタとして呼び出すのと同じ効果があります。

関数の引数

デフォルト引数

関数のデフォルト引数は、関数に値が渡されない場合や undefined が渡される場合に、デフォルト値で初期化される形式上の引数を指定できます。詳細はデフォルト引数を参照してください。

Rest parameters

rest parameters とは、不特定多数の引数を配列として受け取る構文です。詳細は rest parameters を参照してください。

arguments オブジェクト

arguments オブジェクトを使って、関数内部で関数の引数を参照することができます。arguments を参照してください。

メソッドを定義する

getter と setter 関数

新しいプロパティの追加をサポートする、どの標準ビルトインオブジェクトあるいはユーザー定義オブジェクトにも、getter(accessor メソッド)や setter (mutator メソッド)を定義することができます。getter と setter を定義するための構文は、オブジェクトリテラル構文を使用します。

get

オブジェクトのプロパティを、そのプロパティが検索されたときに呼び出される関数に束縛します。

set
オブジェクトのプロパティを、そのプロパティに代入しようとしたときに呼び出される関数に束縛します。

メソッド定義構文

ECMAScript 2015 からは、独自のメソッドを、getter と setter に似た、より短い構文で定義することができます。詳細はメソッド定義を参照してください。

var obj = {
  foo() {},
  bar() {}
};

コンストラクタか関数宣言か関数式か

以下のものを比較してみて下さい。

Function コンストラクタによって定義され、変数 multiply に代入された関数:

var multiply = new Function("x", "y", "return x * y;");

multiply と命名された関数の 関数宣言:

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

変数 multiply に代入された、無名関数の関数式:

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

変数 multiply に代入された、func_name と命名された関数式:

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

相違点

これらは全ておおよそ同じ働きをしますが、いくつか微妙に異なる点があります。

関数名と関数が代入された変数の間には違いがあります。関数名は変える事ができませんが、関数が代入された変数は再代入する事ができます。関数名は関数本体の内部でのみ使用する事ができます。関数本体の外側でそれを使用しようとするとエラー (その関数名がそれより前に var 文によって宣言されていれば undefined ) になります。例えば、

var y = function x() {};
alert(x); // エラーを投げる

関数名は Function の toString メソッドによってシリアライズしたときにも現れます。

一方、関数が代入された変数はそのスコープ内でのみ有効で、そのスコープは関数が宣言されたスコープを含んでいる事が保証されています。

4 つめの例にあるように、関数名はその関数が代入される変数と違っていても構いません。お互いの間に関連性は有りません。関数宣言は同時にその関数名と同じ名前の変数を作成します。よって、関数式で定義されたものと違って、関数宣言で定義された関数は定義されたスコープ内でその名前によってアクセスできます。

new Function によって定義された関数は関数名を持ちません。しかし、JavaScript エンジンの SpiderMonkey では、その関数をシリアライズされた形式にすると "anonymous" という名前を持っているかのように表示されます。例えば、alert(new Function()) はこのように出力されます。

function anonymous() {
}

この関数は実際には名前を持っていないので、anonymous は関数内部でアクセスできる変数ではありません。例えば、次の文はエラーになります。

var foo = new Function("alert(anonymous);");
foo();

関数式や Function コンストラクタで定義されたものとは違い、関数宣言で定義された関数は、関数自体が宣言される前に使用する事ができます。例えば、

foo(); // FOO! とアラートされる
function foo() {
   alert('FOO!');
}

関数式で定義された関数は現在のスコープを継承します。つまり、関数がクロージャを形成します。一方、Function コンストラクタで定義された関数は (あらゆる関数が継承する) グローバルスコープ以外はどんなスコープも継承しません。

 

/*
 * Declare and initialize a variable 'p' (global)
 * and a function 'myFunc' (to change the scope) inside which
 * declare a varible with same name 'p' (current) and
 * define three functions using three different ways:-
 *     1. function declaration
 *     2. function expression
 *     3. function constructor
 * each of which will log 'p'
 */
var p = 5;
function myFunc() {
    var p = 9;

    function decl() {
        console.log(p);
    }
    var expr = function() {
        console.log(p);
    };
    var cons = new Function('\tconsole.log(p);');

    decl();
    expr();
    cons();
}
myFunc();

/*
 * Logs:-
 * 9  - for 'decl' by function declaration (current scope)
 * 9  - for 'expr' by function expression (current scope)
 * 5  - for 'cons' by Function constructor (global scope)
 */

関数式と関数宣言で定義された関数は一度しか解析されませんが、Function コンストラクタで定義された関数はそうではありません。つまり、Function コンストラクタに渡された関数本体を表す文字列が、評価されるたびに必ず解析されます。関数式は毎回クロージャを作成しますが、関数本体は再解析されないので、"new Function(...)" よりは関数式の方がまだ高速です。したがって Function コンストラクタはできる限り避けるべきでしょう。

ただし、Function コンストラクタの文字列を解析することで生成された関数内で入れ子にされている関数式や関数宣言は、繰り返し解析されないことに注意してください。例えば:

var foo = (new Function("var bar = \'FOO!\';\nreturn(function() {\n\talert(bar);\n});"))();
foo(); // 関数本体の文字列で "function() {\n\talert(bar);\n}" の部分は再解析されません

関数宣言はとても簡単に (しばしば意図せずに) 関数式に変化します。関数宣言は以下のような時には関数宣言ではなくなります。

  • 式の一部になった時
  • 関数またはスクリプト自体の「ソース要素 (source element)」でなくなった時。「ソース要素」はスクリプトや関数本体の中で入れ子にされていない文の事です。
var x = 0;               // ソース要素
if (x === 0) {           // ソース要素
   x = 10;               // ソース要素ではない
   function boo() {}     // ソース要素ではない
}
function foo() {         // ソース要素
   var y = 20;           // ソース要素
   function bar() {}     // ソース要素
   while (y === 10) {    // ソース要素
      function blah() {} // ソース要素ではない
      y++;               // ソース要素ではない
   }
}

// 関数宣言
function foo() {}

// 関数式
(function bar() {})

// 関数式
x = function hello() {}


if (x) {
   // 関数式
   function world() {}
}


// 関数宣言
function a() {
   // 関数宣言
   function b() {}
   if (0) {
      // 関数式
      function c() {}
   }
}

ブロックレベル関数

ES2015 で始まった strict モードでは、ブロック内の関数はそのブロックに新しいスコープを形成します。ES2015より前では、ブロックレベル関数は strict モードでは禁止されています。

'use strict';

function f() { 
  return 1; 
}

{  
  function f() { 
    return 2; 
  }
}

f() === 1; // true

// 非 strict モードでは f() === 2

非 strict コードにおけるブロックレベル関数

一言、使わないでください。

非 strict コードでは、ブロック内の関数宣言は奇妙な動作をします。次の例を見てください。

if (shouldDefineZero) {
   function zero() {     // 危険: 互換性リスク
      console.log("This is zero.");
   }
}

ES2015 では shouldDefineZero が false の場合、 このブロックが実行されることはないので、zero は決して定義されないとされています。しかし、これは標準において新しいパーツです。歴史的には、このことは仕様とならないまま残されていました。いくつかのブラウザでは、ブロックが実行されてもされなくても、zero を定義したでしょう。

strict モードでは、ES2015 をサポートする全てのブラウザは、これを同じように扱います。zeroshouldDefineZero が true の場合のみ定義され、かつ if ブロックのスコープに限られます。

条件付きで関数を定義するより安全な方法は、変数に関数式を代入することです。

var zero;
if (0) {
   zero = function() {
      console.log("This is zero.");
   };
}

フォーマットされた数値を返す

次の関数は、数値の先頭にゼロを足して固定長にした形で表される文字列を返します。

// この関数は先頭にゼロを足して固定長にした文字列を返す
function padZeros(num, totalLen) {
   var numStr = num.toString();             // 戻り値を文字列に初期化する
   var numZeros = totalLen - numStr.length; // ゼロの数を計算する
   for (var i = 1; i <= numZeros; i++) {
      numStr = "0" + numStr;
   }
   return numStr;
}

次の文で padZeros 関数を呼び出します。

var result;
result = padZeros(42,4); // "0042" を返す
result = padZeros(42,2); // "42" を返す
result = padZeros(5,4);  // "0005" を返す

関数が存在するかどうか確認する

typeof 演算子を使うと関数が存在するかどうかを確かめる事ができます。次の例では、window オブジェクトが noFunc という関数のプロパティを持つかどうかを確かめるためのテストが行われます。もし持っていたら、それが使われます。そうでなければ、他の行動が取られます。

 if ('function' == typeof window.noFunc) {
   // noFunc() を使う
 } else {
   // 何か他のことをする
 }

if のテストの中で、noFunc への参照が使われているのに注目してください。関数名の後に括弧 "()" が無いので、実際の関数は呼ばれません。

仕様

仕様 状況 コメント
ECMAScript 1st Edition (ECMA-262) 標準 初めての定義。JavaScript 1.0 で実装
ECMAScript 5.1 (ECMA-262)
Function Definition の定義
標準  
ECMAScript 2015 (6th Edition, ECMA-262)
Function definitions の定義
標準 New: アロー関数、ジェネレータ関数、デフォルト引数、rest parameters
ECMAScript Latest Draft (ECMA-262)
Function definitions の定義
ドラフト  

ブラウザ実装状況

機能ChromeEdgeFirefoxInternet ExplorerOperaSafari
基本対応 あり あり1 あり あり あり
arguments あり あり1 あり あり あり
Arrow functions45 あり221 2 なし3210
Block-level functions ? ?46 ? ? ?
Default parameters491415 なし3610
Method definitions39 あり34 なし26 なし
Rest parameters471215 なし3410
get1 あり299.53
set1 あり299.53
機能Android webviewChrome for AndroidEdge mobileFirefox for AndroidOpera AndroidiOS SafariSamsung Internet
基本対応 あり あり あり4 あり あり あり
arguments あり あり あり4 あり あり あり
Arrow functions4545 あり221 232105.0
Block-level functions ? ? ?46 ? ? ?
Default parameters4949141536105.0
Method definitions3939 あり3426 なし4.0
Rest parameters4747121534105.0
get118 あり4 あり あり あり
set118 あり4 あり あり あり

1. The initial implementation of arrow functions in Firefox made them automatically strict. This has been changed as of Firefox 24. The use of 'use strict'; is now required.

2. Prior to Firefox 39, a line terminator (\n) was incorrectly allowed after arrow function arguments. This has been fixed to conform to the ES2015 specification and code like () \n => {} will now throw a SyntaxError in this and later versions.

3. From version 4.0.0: this feature is behind the --harmony runtime flag.

関連情報

ドキュメントのタグと貢献者

このページの貢献者: Uemmra3, sii, teoli, yyss, ethertank, Potappo, Nanto vi, Shoot, Mgjbot, Taken, Hfjapancom
最終更新者: Uemmra3,