JavaScriptと高階関数
高階関数とは?
高階関数(こうかいかんすう、英: higher-order
http://ja.wikipedia.org/wiki/%E9%AB%98%E9%9A%8E%E9%96%A2%E6%95%B0
function)とは、プログラミング言語において、関数を引数にしたり、あるいは関数を戻り値とするような関数の事である。引数や戻り値の関数もまた高階関数となり得る。これは主に関数型言語やその背景理論であるラムダ計算において多用される。数学でも同様の概念はあり、汎関数と呼ばれる。
関数返しの関数
高階関数という言葉を知らなくても、関数を引数にしたり、関数を戻り値とする関数には最近のライブラリーなどでよく見るようになりました。数式や入力チェックなどで高階関数を利用することは稀で僕は基本使いません。
僕が高階関数を利用するときは、大抵IEやFirefoxで互換のある関数を作成するときやイベントハンドラの生成のときに利用します。
// addEvent1 addEvent1 = function(element, eventtype, lambda) { if(document.addEventListener) { // firefox, safar, operaなど element.addEventListener(eventtype, lambda); } else { // IE用 element.attachEvent('on' + eventtype, lambda); }; }; // addEvent2 addEvent2 = function() { // firefox, safari, operaなど if(document.addEventListener) { return function(element, eventtype, lambda){ element.addEventListener(eventtype, lambda); }; }; // IE用 return function(element, eventtype, lambda){ element.attachEvent('on' + eventtype, lambda); }; }; // 再定義 addEvent2 = addEvent2();
上記コードでは、addEvent1では関数が呼び出される度に毎回ブラウザー分岐を行っているのに対して、addEvent2では、最初の再定義の段階で一度だけブラウザー分岐を行いそれ以降は、そのブラウザに適した関数のみを実行します。
実際には
addEvent2は上記例のように再度代入することは稀で以下のように関数の宣言と同時に関数を定義します。YUIのコードでも多様されています。
addEvent2 = function() { // firefox, safari, operaなど if(document.addEventListener) { return function(element, eventtype, lambda){ element.addEventListener(eventtype, lambda); }; }; // IE用 return function(element, eventtype, lambda){ element.attachEvent('on' + eventtype, lambda); }; }(); //上記の()がポイント // alert(addEvent2); // IEでは element.attachEvent〜が表示される
関数を引数にとる関数
ところで関数を引数にとる関数というのもあります。average関数で第一引数に指定した関数を内部的に呼び出し、average関数の第二引数と第三引数をsum関数に渡しています。
function sum(a, b){ return (a + b); }; function average(func, a, b){ return (func(a, b) / func.length); }; average(sum, 4, 2); // 3
addEventListenerの第二引数
addEventListnerを用いると関数を引数にとるという行為は当然のように行われてきます。日本語に訳にするdocumentオブジェクトがクリックされたときのイベントにonClickHandler関数を追加するという意味にでもなりますか。
var onClickHandler = function(e){ alert(e); }; document.addEventListener('click', onClickHandler); document.addEventListener('click', function(e){ alert("Hoge"); });
というわけで
高階関数という概念や言葉を知らなくてもJavaScriptでは高階関数を知らず知らず使っています。
補足
- 上記addEventのコードではIEで利用したときにthisの参照がwindowオブジェクトになってしまうので完全に互換性のあるコードではありません。
- このエントリーはカリー化の説明に対する前振りです。