JavaScript/関数

出典: フリー教科書『ウィキブックス(Wikibooks)』
ナビゲーションに移動 検索に移動

関数(かんすう、function)とは、コードのまとまりです。

概要[編集]

関数はプログラムの中に繰り返し現れるような同じコードや、意味がそろっているコードを一つの手続きとしてまとめるために用いられます。JavaScriptの関数はfunction文を使って定義します。

function add(a, b) {
    var sum = a + b;
    return sum;
}

var three = add(1, 2); // 1 + 2
alert(three); // 3

これは数値a, bを受け取り、abを足した結果sumを返すadd関数の例です。abのように関数が受け取るデータを引数(ひきすう、parameter)、sumのように関数が返す値を戻り値(もどりち、return value)あるいは返り値(かえりち)といいます。戻り値はreturn文を使って返します。

関数を呼び出すには、add(1, 2)のように関数の名前の後に()を付けて、()の中に引数として関数に渡す値を入れます。関数が呼び出されると、1はa、2はbに代入されて、関数の本体が実行され、足し算の結果が返されます。

abのように関数が受け取ると仮定された引数を仮引数(かりひきすう、かびきすう、parameter)、1や2のように関数に実際に渡した引数を実引数(じつひきすう)といいます。余裕のある人は憶えてください。

関数リテラル[編集]

JavaScriptにおける関数はオブジェクトobject)の一種であり、ArrayオブジェクトやStringオブジェクトなど、他のオブジェクトと同じように操作することができます。

var add = function(a, b){
    return a + b;
};

alert( add(1, 1) ); // 1 + 1 == 2

このようなオブジェクトを第一級オブジェクト(だいいっきゅうオブジェクト、first-class object)といいます。JavaScriptは関数を第一級オブジェクトとして扱えるので、第一級関数(だいいっきゅうかんすう、first-class function)をサポートしています。

関数スコープ[編集]

関数の中でvarキーワードを用いて宣言された変数は、関数の中からしか見えません。

var f = function(){
    var i = 0;
    return i;
};

alert( f() ); // 0
alert(i);     // 参照エラー

言い換えれば、関数の中でvarキーワードを用いて宣言された変数と、関数の外で宣言された変数は別物です。

var f = function(){
    var i = 0;
    return i;
};

var i = 1;
alert(i);     // 1
alert( f() ); // 0

Function[編集]

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

var add = new Function('a', 'b', 'return a + b');
alert( add(1, 1) ); // 1 + 1 == 2

Functionオブジェクトのコンストラクタは最初に仮引数を表す文字列をいくつか受け取り、最後の引数として関数の本体を表す文字列を受け取ります。

プロパティ[編集]

Functionオブジェクトのプロトタイプです。

標準グローバル関数[編集]

decodeURI
decodeURIComponent
encodeURI
encodeURIComponent
eval
isFinite
isNaN
parseFloat
parseInt
void

再帰[編集]

再帰とは、関数が自分自身を呼び出すことをいいます。

// 階乗 n!
function factorial(n) {
    return n
         ? n * factorial(n - 1)
         : 1;
}
alert( factorial(5) ); // 120

// n 番目のフィボナッチ数
function fibonacci(n) {
    return n < 2
         ? n
         : fibonacci(n - 2) + fibonacci(n - 1);
}
alert( fibonacci(10) ); // 55

// a, b の最大公約数
function gcd(a, b) {
    return b
         ? gcd(b, a % b)
         : Math.abs(a);
}
alert( gcd(42, 56) ); // 14

脱出条件を間違えて無限ループにならないように注意してください。

無名関数[編集]

無名関数(むめいかんすう)または匿名関数(とくめいかんすう、anonymous function)とは、名前のない関数を指します。

(function(a, b){
    alert(a + b); // "3" と警告
})(1, 2);

無名再帰[編集]

無名関数の再帰を無名再帰(むめいさいき)または匿名再帰(とくめいさいき、anonymous recursion)といいます。JavaScriptで無名再帰を行うには、関数の中で自分自身を指すarguments.calleeプロパティを使用します。

// 階乗 n!
(function(n){
    return n
         ? n * arguments.callee(n - 1)
         : 1;
})(5);

// n 番目のフィボナッチ数
(function(n){
    return n < 2
         ? n
         : arguments.callee(n - 2) + arguments.callee(n - 1);
})(10);

// a, b の最大公約数
(function(a, b){
    return b
         ? arguments.callee(b, a % b)
         : Math.abs(a);
})(42, 56);

arguments.calleeプロパティを使用せずに無名再帰を行うには、不動点コンビネータ(ふどうてんコンビネータ、fixed point combinator不動点演算子、ふどうてんえんざんし、fixed-point operator)を用います。

// 不動点コンビネータ
var Z = function(f){
    return function(x){
        return function(y){
            return f( x(x) )(y);
        };
    }(function(x){
        return function(y){
            return f( x(x) )(y);
        };
    });
};

// 階乗 n!
Z(function(f){
    return function(n){
        return n
             ? n * f(n - 1)
             : 1;
    };
})(5);

// n 番目のフィボナッチ数
Z(function(f){
    return function(n){
        return n < 2
             ? n
             : f(n - 2) + f(n - 1);
    };
})(10);

// a, b の最大公約数
Z(function(f){
    return function(a){
        return function(b){
            return b
                 ? f(b)(a % b)
                 : Math.abs(a);
        };
    };
})(42)(56);

ラムダ計算も参照してください。

クロージャ[編集]

クロージャclosure、閉包、へいほう)とは、引数以外のすべての変数を静的スコープ(せいてきスコープ、static scoping構文スコープlexical scopingレキシカルスコープ)で解決する関数のことです。教科書などによく出てくる典型的なクロージャは、次のようなカウンタ変数を用いた例です。

// 関数を返す関数
var f = function(){
    var i = 0;
    return function(){
        return i++;
    };
};

var g = f();
alert( g() ); // 0
alert( g() ); // 1
alert( g() ); // 2
var i = 0;    // カウンタ変数を書き換えても
alert( g() ); // 3 -- 値は変わらない

関数fは変数iをインクリメントして返す関数を返す関数です。ややこしいですが、fによって生成された関数gを呼び出すと、iの値が0, 1, 2, ...と1ずつ増やして返されます。ここでiの値を書き換えても、gの中のiの値は変わりません。gはクロージャになっているからです(gを呼び出したときではなく、gを定義したときのiを参照している)。

関数fの中の変数iに注目してください。ifの中でvarキーワードを用いて宣言されているので、関数スコープになり、fを出た時点で消滅するはずです。しかし、関数gを呼び出すとなおiをインクリメントした値が返ってきます。繰り返しになりますが、クロージャとは引数以外のすべての変数を、呼び出した時点ではなく定義した時点で解決する関数のことでした。fが返す関数を定義した時点ではiが生きていたので、iが見えなくなってもiの値を参照しつづけられるというわけです。

このページ「JavaScript/関数」は、書きかけです。加筆・訂正など、協力いただける皆様の編集を心からお待ちしております。また、ご意見などがありましたら、お気軽にノートへどうぞ。