一般的に言うと、関数とは外部 (再帰の場合は内部) から 呼ばれる ことのできる「サブプログラム」です。プログラムそのもののように、関数は関数本体と呼ばれる連続した文で構成されます。値を関数に 渡す 事ができ、関数は値を返す事ができます。
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 (arg1, arg2, ... argN, functionBody)
arg1, arg2, ... argN
- 関数で仮引数名として使われる、0 個以上の名前。それぞれが、妥当な JavaScript 識別子に相当する文字列、もしくはそういった文字列のカンマで分割されたリストでなくてはなりません。例えば "
x
" 、"theValue
"、もしくは "a,b
" などです。
functionBody
- 関数定義を構成する JavaScript 文を含む文字列。
Function
コンストラクタを関数として (new
演算子を使わずに) 呼び出しても、コンストラクタとして呼び出すのと同じ効果があります。
関数の引数
デフォルト引数
関数のデフォルト引数は、関数に値が渡されない場合や undefined
が渡される場合に、デフォルト値で初期化される形式上の引数を指定できます。詳細はデフォルト引数を参照してください。
Rest parameters
rest parameters とは、不特定多数の引数を配列として受け取る構文です。詳細は rest parameters を参照してください。
arguments
オブジェクト
arguments
オブジェクトを使って、関数内部で関数の引数を参照することができます。arguments を参照してください。
arguments
: 現在実行中の関数に渡された引数を格納する配列風オブジェクト。arguments.callee
: 現在実行中の関数。arguments.caller
: 現在実行中の関数を実行した関数。arguments.length
: 関数に渡された引数の数。
メソッドを定義する
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 をサポートする全てのブラウザは、これを同じように扱います。zero
は shouldDefineZero
が 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 の定義 |
ドラフト |
ブラウザ実装状況
機能 | Chrome | Edge | Firefox | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|---|
基本対応 | あり | あり | 1 | あり | あり | あり |
arguments | あり | あり | 1 | あり | あり | あり |
Arrow functions | 45 | あり | 221 2 | なし | 32 | 10 |
Block-level functions | ? | ? | 46 | ? | ? | ? |
Default parameters | 49 | 14 | 15 | なし | 36 | 10 |
Method definitions | 39 | あり | 34 | なし | 26 | なし |
Rest parameters | 47 | 12 | 15 | なし | 34 | 10 |
get | 1 | あり | 2 | 9 | 9.5 | 3 |
set | 1 | あり | 2 | 9 | 9.5 | 3 |
機能 | Android webview | Chrome for Android | Edge mobile | Firefox for Android | Opera Android | iOS Safari | Samsung Internet |
---|---|---|---|---|---|---|---|
基本対応 | あり | あり | あり | 4 | あり | あり | あり |
arguments | あり | あり | あり | 4 | あり | あり | あり |
Arrow functions | 45 | 45 | あり | 221 2 | 32 | 10 | 5.0 |
Block-level functions | ? | ? | ? | 46 | ? | ? | ? |
Default parameters | 49 | 49 | 14 | 15 | 36 | 10 | 5.0 |
Method definitions | 39 | 39 | あり | 34 | 26 | なし | 4.0 |
Rest parameters | 47 | 47 | 12 | 15 | 34 | 10 | 5.0 |
get | 1 | 1 | あり | 4 | あり | あり | あり |
set | 1 | 1 | あり | 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 until version 6 (exclusive): this feature is behind the --harmony-rest-parameters
runtime flag.