関数 (Functionオブジェクト)

JavaScriptの関数の実体は、Functionオブジェクトです。

Functionオブジェクト

プロパティ
プロパティ 内容
caller 呼び出し元の関数
constructor オブジェクトを生成した関数
arguments (非推奨) 引数の配列
lenth 引数の数
name 関数の名前
メソッド
メソッド 説明
apply 関数を呼び出す (引数は配列)
call 関数を呼び出す (引数は変数の羅列)
toSource 関数のソースコードを返す
toString

関数の定義

関数は、functionキーワードにより定義できます。

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

関数リテラル (Function literal)

関数リテラルでは関数名を省略できます。このように定義された関数は、

  • 匿名関数 (Anonymous Function)
  • 無名関数 (Nameless Function)
  • ラムダ関数 (Lambda Function)

などと呼ばれ、変数に格納したり他の関数に渡すためにだけ定義される関数の記述に適しています。

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

なおJavaScript 1.5以降では関数リテラルでも関数名を付けることができ、再帰関数を作ることができます。

参考

Function()コンストラクタ

関数を実行時に動的に生成できます。以下のコードは、前述のコードと同義のものです。

var FunctionName = new Function( 'x', 'y', 'return x * y;' );

関数の作成はfunctionではなくFunctionで行います。そして最後の引数が関数の本体となります。

多重定義

JavaScriptにはC++のような関数の多重定義はなく、同名の関数を定義すると、先の関数が上書きされて呼び出せなくなります。

function Func( a )    { alert( a ); }
function Func( a, b ) { alert( a + b ); }

Func( 'X' ); // Xundefined

この例では後から定義された関数Func()が呼び出され、引数の数が不足しているため第2引数がundefinedとなっています。

JavaScriptでの多重定義の実現方法

多重定義はサポートされていませんが、Argumentsなどで関数側で細工をすれば、多重定義されているように振る舞わせることは可能です。

function Func1()
{
    switch( arguments.length )
    {
        case 1:
            // 引数が1つの場合の処理
            break;

        case 2:
            // 引数が2つの…
            break;
    }
}
function Func2( a )
{
    switch( typeof a )
    {
        case 'number':
            // 引数が数値の場合の処理
            break;

        case 'string':
            // 引数が文字列の…
            break;
    }
}

ゲッターとセッター (Getter and setter)

オブジェクトのプロパティへアクセスするための関数 (メソッド) の代替として、ゲッター (accessor methods) とセッター (mutator methods) を定義できます。これは、C#のプロパティに相当する機能です。

Internet Explorerの場合、ゲッターとセッターにはIE9以降で対応します。

{get prop() { ... } }
getter - JavaScript | MDN
{set prop(val) { . . . }}
setter - JavaScript | MDN

たとえばゲッターは次のように定義でき、プロパティと同様にアクセスできるのにもかかわらず、より柔軟な結果を返せます。

var a = 1;
var obj =
{
    x: a,                  // プロパティ
    get y () { return a; } // ゲッター
}

alert( obj.x ); // 1
alert( obj.y ); // 1

a = 2;

alert( obj.x ); // 1 … オブジェクト定義時の値を返す
alert( obj.y ); // 2 … 現在の値を返す

アロー関数式 (Arrow function expression)

アロー関数式、別名ファットアロー関数 (fat arrow function) を用いることで、関数を簡潔に記述できます。またthisのスコープを、その関数内に制限します。Arrow functions - JavaScript | MDN

([param] [, param]) => {
   statements
}
param => expression

このアロー関数式には2013年6月現在、Firefoxしか対応していませんBrowser compatibility - Arrow functions - JavaScript | MDN

このアロー関数式を用いると、たとえば次のような文字列中の特定の文字のみを大文字に置換するコードは、

var newText = text.replace( /[a-c]/g,
    function( str )
    {
        return str.toUpperCase();
    } );

functionキーワードを省いて次のように書き換えられます。

var newText = text.replace( /[a-c]/g,
    ( str ) => {
        return str.toUpperCase();
    } );

さらにこの場合かっことreturnも省けるため、結果として次のようになります。

var newText = text.replace( /[a-c]/g,
    str => str.toUpperCase()
    );

関数のスコープ

関数の実行スコープは、実行時のスコープではなく定義時のスコープです。

関数を入れ子で定義したスコープチェーンには、入れ子関数の外側の関数が含まれるようになります。これにより入れ子にされた関数からは、外側の関数の引数やローカル変数にアクセスできます。

Callオブジェクト

関数が呼び出されると、関数のスコープには関数定義時のスコープチェーンが追加され、次にCallオブジェクトがその先頭に追加されます。

var x; // グローバルオブジェクト
function Func()
{
    var x; // Func()のCallオブジェクト
}

即時実行関数式 (Immediately-invoked function expression : IIFE)

グローバルな空間での変数名やプロパティ名の衝突を避けるには、

( function( str ) // 匿名関数として定義
{
    var a = str;  // この変数はこのスコープ内でのみ有効

} )( 'abc' );    // ここで関数が実行される

のように匿名関数を定義して実行します。この方法は他にも、

!function() { /* */ }();
~function() { /* */ }();
-function() { /* */ }();
+function() { /* */ }();

のように記述できます。どれを選ぶかは好みですが、最初の「!」から始める方法が一般的のようです。

引数

引数の数

JavaScriptでは関数呼び出し時の引数の数は、問題とされません。

  • 呼び出し側の引数が多すぎた場合、その引数は無視されます。
  • 呼び出し側の引数が少なすぎた場合、不足している引数に未定義値 (undefined) が設定されます。
function FunctionName( x, y ) // 引数は2つ
{
    alert( x ); // 結果は 10
    alert( y ); // 結果は undefined
}

// 引数を1つだけ指定して、関数を呼び出す
FunctionName( 10 );

なお呼び出された関数側では、arguments.lengthで渡された引数の数を知ることができます。

値渡しと参照渡し

C言語のように引数の渡し方を明示的に指示する方法はなく、つねに値渡しです。オブジェクトも値渡しであり、それ自身の変更は呼び出し元へ影響しませんが、そのプロパティへの変更は呼び出し元へ作用します。

function Func( a, b, c )
{
    a = 2;
    b = {p: 2};
    c.p = 2;
}

var x = 1;
var y = {p: 1};
var z = {p: 1};

Func( x, y, z );

alert( x );   // 1
alert( y.p ); // 1
alert( z.p ); // 2 (呼び出し元へ作用する)

デフォルト引数 (Default parameters)

function fnName(param1 = defaultValue1, ..., paramN = defaultValueN) { /* ... */ }

ECMAScript 2015 (ES2015) 以降で使用できます。デフォルト引数 - JavaScript | MDN

非対応の環境では、次のようにundefinedのときに既定値を指定するようにします。

param1 = typeof param1 !== "undefined" ? param1 : defaultValue1;

Argumentsオブジェクト

関数内では、arguments変数によりArgumentsオブジェクトを参照できます。Argumentsオブジェクトは番号付けされたプロパティを持ち、これにより関数に渡された引数に配列のようにアクセスできます。

function Func( a, b, c )
{
    alert( a );  // 1
    alert( b );  // 2
    alert( c );  // undefined

    alert( arguments );  // [1, 2]
}

Func( 1, 2 );
変数名 説明
arguments 関数に渡された引数を格納しているオブジェクト
arguments.length 関数に渡された引数の数
arguments.callee (非推奨) 実行中の関数への参照
arguments.caller (廃止) 実行中の関数の呼び出し元の関数への参照
関数内部のローカル変数 - 関数と関数スコープ - JavaScript | MDN

arguments.calleeプロパティ (再帰呼び出し)

arguments.calleeは現在実行中の関数を参照しているため、これを使用することで名前がない関数も参照できます。また再帰呼び出しにも利用できます。

var func = function( x )
{
    if( x < 2 )
    {
        return 1;
    }
    else
    {
        // 関数func()を呼び出す
        return x * arguments.callee( x - 1 );
    }
}

alert( func( 5 ) );

ECMAScript 5のStrictモードでは、calleeの使用が禁止されています。よってcalleeは使用せず、関数の名前で呼び出すようにします。arguments.callee - JavaScript | MDN

グローバル関数 (Global Functions)

  • decodeURI()
  • decodeURIComponent()
  • encodeURI()
  • encodeURIComponent()
  • escape() (非推奨)
  • unescape() (非推奨)
  • eval()
  • getClass()
  • isFinite()
  • isNan()
  • parseFloat()
  • parseInt()
JavaScriptのドキュメントから検索