JavaScriptをしっかり勉強 vol.5 コールバック関数

プログラム
date 2014.05.29 tag JavaScript

JavaScriptを勉強したことを書いていくエントリーvol.5です。今回はコールバック関数について書いていきます。

コールバック関数とは

JavaScriptではコールバック関数が多用されます。コールバック関数とはあらかじめ関数を登録しておき、ある特定のタイミングでその関数が呼ばれ、実行されるものです。 言葉では分かりにくいと思うのでまずはコードを書いてみます。

js通常の関数呼び出しとコールバック関数呼び出し

//関数の定義
function callBackFunction() {
  result.innerHTML += 'called callBackFunction<br>';
}

//関数「callBackFunction」を呼び出す
callBackFunction();

var lisner = {
  //関数「callBackFunction」を登録(格納)する
  //この時点では呼び出さない
  exec : function() {
    callBackFunction();
  }
}

//lisner.execメソッドによって関数「callBackFunction」が呼び出される
lisner.exec();

関数を呼び出す場合と、呼び出される場合の感覚が何となく掴めてきたと思います。この場合、呼び出される関数のことを「コールバック関数」と言います。このコードでは明示的にコールバック関数を呼び出していますが(コールバック関数と表現すると受動態ではなくなる)、JavaScriptでは主にイベントに基づきコールバック関数を呼び出します。

JavaScriptはプログラムの特徴としてイベントドリブン(Event Driven)と呼ばれるモデルを採用しています。これはイベントをもとに処理(関数)が駆動するモデルです。onclickとかよく見るあれのことで、このようなイベントが発生すると登録してあるコールバック関数を実行する仕組みになっています。

イベントハンドラとイベントリスナ

イベントに対して実行されるコールバック関数を「イベントハンドラ」あるいは「イベントリスナ」と言います。横文字が並びましたが、この2つは役割が違います。具体的にはこのような感じ。

コールバック関数 意味
イベントハンドラ 1つのイベントに対して1つの関数しか設定できない。
イベントリスナ 1つのイベントに対して複数の関数呼び出しを設定できる。

イベントハンドラ

イベントハンドラは主要ブラウザはIE6を含むほぼ全てで使用することができます。ただし1つのイベントに対して1つのコールバック関数(イベントハンドラ)が割り当てられる挙動をするため、イベントハンドラが上書きされてしまう可能性があります。

これもまずコードを書いてみます。イベントハンドラは要素のプロパティに対して代入して設定し、プロパティは基本的に「on(イベント名)」の命名となっています。

JSイベントハンドラの実装例

//出力用フィールの取得
var button = document.getElementById('target');
button.onclick = function() {
  alert('onclick');
}

//このイベントハンドラに上書きされる
button.onclick = function() {
  this.innerHTML = 'onclick';
}

このコードのように1つのイベントに複数のイベントハンドラが登録されると、上書きが発生してしまいます。

イベントリスナ

逆にイベントリスナは1つのイベントに対して複数のイベントリスナ(コールバック関数)を設定することができます。1つのイベントに対して2つ以上のイベントリスナが登録された場合はコードの上からの登録順で実行されます。

こちらもコードを書いてみましょう。取得した要素に対して「addEventLister」メソッドでイベントリスナを設定します。addEventListerには次の引数を設定します。

callback

イベントハンドラとは異なり、イベントの命名に「on」は付きません。また第3引数のcapture_flagはイベントの伝播に関するフラグのようです。(あまり深く調べていないすw)デフォルト値がfalseのため、明示的にfalseを設定しています。

JSイベントリスナの実装例

//出力用フィールの取得
var button = document.getElementById('target');

//イベントリスナの登録
button.addEventListener('click', function() {
  alert('click');
}, false);

//イベントリスナを2つ登録
button.addEventListener('click', function() {
  this.innerHTML = 'click'
}, false);

イベントリスナを使ったこのコードではまずalertが実行されてから、ボタンのテキストが変更されます。コードの上から順にイベントが上書きされること無く実行されることを確認できます。

イベントリスナ使用の考慮点

イベントリスナの登録はaddEventListerを使用しますが、これはIE7では利用できません。addEventListerは標準規格のものですが、IE7では独自規格のattachEventを実装しています。使用するケースによりますがときにaddEventListerを使うのはリスクが伴います。

※あくまでネイティブなJavaScriptコードを書く場合。独自にaddEventLister/attachEvent切り分け関数を作るのも可能ですし、jQueryのライブラリではこの違いを意識する必要はありません。