JavaScriptの関数は、数値、文字列、配列などのオブジェクトと同じように扱う事が可能です。すなわち
などの性質があります。このような性質を持つオブジェクトはファーストクラス(第一級)オブジェクトと呼ばれ、JavaScriptでは関数もファーストクラスオブジェクトとして実装されています。
現在(2009年)のJavaScriptプログラミングではファーストクラスオブジェクトとしての関数の性質がよく利用されており、関数をオブジェクトとして上手く使う事が上手いコーディングのキモといってもいいほどポピュラーになっています。
関数を変数に代入する
function fuga() { window.alert("fuga") } var f = fuga; f();
無名関数を変数に代入
var hoge = function() { window.alert("hoge"); } hoge();
言語によって無名関数の定義はラムダ式と呼ばれる事もありますが、JavaScriptではあまりそう呼ばれることがありません。
メソッドの定義
var obj = new Object(); obj.x = 1 obj.y = 2 obj.sum = function() { return this.x + this.y } obj.sum(); // => 3
オブジェクトのプロパティとして関数をセットしたものがメソッドです。
関数自身がオブジェクトであるため、普通のオブジェクトのようにメソッドを定義したり、プロパティを付加したりできます。
// 関数fugaがプロパティcountを持っている。 function fuga() { window.alert(fuga.count++); } fuga.count = 0;
高階関数とは、関数を引数にする関数や、関数を戻り値にする関数です。
Array#sort メソッドは関数を引数にするメソッドの代表です。
var array1 = [3,5,4,1,2]; array1.sort(function(a, b){ return a - b }); // 降順ソート var array2 = [4,3,2,5,1]; array2.sort(function(a, b){ return b - a }); // 昇順ソート
Javaのように関数をオブジェクトとして利用することができない(難しい)言語ではストラテジーパターンで代用されています。Javaで配列をソートする場合、Comparatorインターフェースの実装クラスを作る必要があり面倒ですが、スクリプト言語は関数やコードブロックを渡すだけで良く、簡潔に記述できます。
カリー化とは、複数の引数をとる関数f(x, y, z, …)があったとき、
f(x, y, z, ....) = g(x)(y)(z) ....
複数の引数を取る関数fを、関数を返すことで1引数の関数の組み合わせで表現する事である。
例
function logarithm(x, y) { return Math.log(y) / Math.log(x); }
これは底をxとする対数 logxy の値を返す関数である。これを1引数の関数に変換してみると…
var logarithmBase = function(x) {
return function(y) {
return logarithm(x, y);
}
};
これを実行すると
logarithmBase(10)(2); // => 0.30102999566398114 var commonLogarithm = logarithmBase(10); commonLogarithm(3); // => 0.47712125471966244
引数が2つの関数logarithmを、1引数の関数の組み合わせに置き換える事が出来ました。
カリー化はJavaScriptプログラミングでは必須の概念ではありませんが、引数が束縛されるという性質を確認するのにうってつけの例です。logarithmBaseの定義を見ると、logarithmBase(10)を実行したときに、あたかも logarithm(x, y) の最初の引数xが10に固定されてしまったかのように見えます。これはクロージャを理解する時に大変重要な性質となります。
関数内 static 変数的な値を作る。 非オブジェクト指向言語におけるstatic変数は関数やブロック内で宣言された変数で、そのブロックが終了しても値を保持している変数のこと。
function hoge () { if(!arguments.callee._staticValue){ arguments.callee._staticValue = 1; } return arguments.callee._staticValue++; } hoge(); // 1 hoge(); // 2 hoge(); // 3 hoge._staticValue; // 3 (外部からアクセスできてしまう)
この実体は単なる関数オブジェクトのプロパティなので外部からでもアクセスできてしまう。あまり奇麗な書き方ではないがグローバル変数を定義するよりマシ。
まともな利用法としては、例えば複数のボタンに対して一つの関数をイベントリスナとし、最後にそのリスナを実行したボタン(のDOM要素)をリスナ自身に記憶させるとか。
// require jQuery function onclickHoge( event ) { arguments.callee.lastEventTarget = event.target; // 何か処理 } $(".hoge").click(onclickHoge); // onclickHogeイベントリスナを最後に実行した要素を取得 var element = onclickHoge.lastEventTarget;