jQuery イベントオブジェクトについて

## 記事の内容
jQueryライブラリのイベントオブジェクトについてメモ程度にまとめる。
(参考:jQuery本格入門 著:沖林正紀 出版:技術評論社)

###イベントオブジェクトとは

JavaScriptのイベントオブジェクトにいくつかメソッドやプロパティを加えて、Webブラウザごとの違いを吸収したもの。
`$.Event`によって生成される。イベント処理が行われる関数の第一引数に渡される。


####マウスカーソルの位置

マウスカーソルを表すイベントプロパティは以下の表のとおりである。

||x|y|
|---|---|---|
|ブラウザ画面内の位置|clientX|clientY|
|Webページ内の位置|pageX|pageY|
|要素内での位置|offsetX|offsetY|
|デスクトップ画面内の位置|screenX|screenY|

#### イベント発火に関連した要素

このプロパティで参照される要素はすべてDOMオブジェクト。
イベント発火した要素と、イベントを処理した要素が違う場合、そのイベントがバブリングしたとわかる。

`target`　イベント発火した要素
`currentTarget`　$(...)で指定された要素のうち、イベントが発火した要素を含むもの。
`relatedTarget` 
・mouseoverイベントの場合
イベント発火直前にマウスカーソルが重なっていた要素。
・mouseoutイベントの場合
イベント発火時点で重なっている要素
`toElement`　マウス移動後の要素
`delegateTarget`　delegateまたはonを実行した$(...)で指定された要素のうち、
イベントが発火した要素を含むもの。

#### イベント処理の中止

`preventDefault()`　イベント処理の最後に`return false`を実行したときのように、フォームの送信や、ページの遷移などを行わない。
`stopImmediateProbagation`　同じイベントに対応するイベント処理が複数登録されていても、その後のイベント処理がされない。
`stopProbagation`　バブリングが起こらなくなる。同じ要素で発火した特定のイベントに対応するイベントは実行される。

#### イベント処理にデータを受け渡す。

イベントオブジェクトをイベント処理を行う関数とは別に、引数としてオブジェクトを設定すると、イベントオブジェクトのdataプロパティの値を参照することができる。

####delegateTargetプロパティ

$(...)で設定した要素のうち、子孫要素にイベントを発火した要素を含むものを表す。

### Deferredオブジェクトによる処理の実行

#### Deferredオブジェクトとは
オブジェクトが持つ状態を別の状態に変化させるときに処理が実行されるように設定できる。

イベント処理はイベント発火前に対応する処理が登録されていなければ、その処理を実行することができないが、Deferredオブジェクトは状態が変化した後で、対応する処理を登録しても、実行される。

`$.Deferred([関数])`で生成される。関数で生成したDeferredオブジェクトに処理を追加できる。

状態と処理キューを持っていて、
オブジェクト生成時には、「保留(pending)」の状態にある。
この状態でも、処理を登録することができる。
「保留(pending)」→「解決済み(resolved)」| 「棄却済み(rejected)」と状態が変化し、状態に応じて、キューに登録されている処理が実行される。遷移した状態を元に戻すことはできない。

##### 処理を登録するメソッド
`done`　状態が解放済みに遷移した後に実行される処理を登録。
`fail`　状態が棄却済みに遷移した後に実行される処理を登録。
`progress`　状態が遷移する前に実行される処理を登録。

それぞれをメソッドチェーンによってつなげて記述することができる。

Deferredオブジェクトの状態の遷移させるメソッドは
`resolve`→解決済み　`reject`→棄却済み　`progress`→保留状態のまま

また`notify`メソッドを実行しても、状態はpendingのままなので、progressで登録された関数は何度でも実行することができる。
一方で解決済み、棄却済みに移行したオブジェクトの状態は戻せないため、done、failで実行した処理は一度しか実行することができない。

Deferredオブジェクトのメソッドは、複数の引数が設定されると、すべてdone、fail、progressで登録した関数の引数に引き継がれる。
複数の処理を同時に設定することもでき、メソッドに複数の引数を設定する、メソッドチェーンを用いる、引数に配列を設定するという方法がある。
実行する順序は、引数の並び、登録順、配列の要素順となっている。

状態を遷移させるメソッドの中で、
`xxxWith`メソッドの第一引数を設定した引数は、処理中のthisキーワードとなる。

現在の状態を表示する
→`deferred.state()`メソッドを使用。

・その他の登録方法
`always(関数[, 関数,...])`
→状態がresolved/rejectedどちらに移動しても、同じ関数を実行する。
`then(関数1　[, 関数2[, 関数3]])`
→1：doneで登録した関数の前に実行するもの、
→2：failで登録した関数の前に実行するもの
→3：notifyで登録した関数の前に実行するものを登録。
中間処理を設定することができる。

####Promiseオブジェクト

状態を遷移させる処理を先に行い、状態に応じた処理の登録を別の処理に委ねるために用意されたオブジェクト。
Deferredオブジェクトから、状態を遷移させるメソッドresolve/reject/notifyを除いたサブセット。
状態と処理キューはそのまま引き継いでいる。

これはアニメーションの動作時や、Ajaxの通信が終了した後に行う処理を設定するときにも利用する。

アニメーションでは、最後の処理が終了すると、Deferredオブジェクトの状態が、resolvedに、
途中で処理が中断されると、rejectedに遷移する。
show/hideメソッドのオプションでしてされるdone,fail,always,progressには、Promissオブジェクトのメソッドと同じ意味でつかわれる。

`promise([オブジェクト])`
→Promiseオブジェクトを生成する。引数にオブジェクトがあると、そのオブジェクトにPromiseオブジェクトのメソッドを追加する。
`$.when(関数[,関数, ...])`
→Promiseオブジェクトを返す処理を登録、すべての関数の処理が終わるまで待機する。


thenメソッドを実行した後では、実は、resolveメソッドを実行することができない。それはthenメソッドの戻り値がpromiseオブジェクトであり、resolveメソッドをもっていないからである。

PromiseオブジェクトはjQueryオブジェクトによる処理が終了するのを待ってから、次の処理を行いたいときに利用することができる。
これによって、
・HTML文書に追加した要素にテキストを補う
・アニメーションが終了してから次の処理を実行する。
などが実現できる。
流れとしては、
・promiseメソッドでPromiseオブジェクトを生成。
・doneでその後に行いたい処理を登録する。

```javascript
//新しく追加した<div>にテキストを補う
$('<div>').appendTo(document.body).promise()
.done(function(){this.text('jQuery'); });

//アニメーション終了後に処理を実行
$('div').slideUp(3000).promise()
.done(function(){alert.'要素が隠れました'); });
```

promiseオブジェクトはアニメーションの終了について管理しているので、複数のオブジェクトがランダムに動く場合などでも、すべてが終了するのを待ってから、その後の処理を一度だけ行うことができる。

##### $.whenメソッド

このメソッドは
一つ、または複数のオブジェクトを引数にとって、
戻り値はPrimiseオブジェクトを返す。
引数のすべてがDeferredオブジェクト、Promiseオブジェクトでない場合、whenに続く、doneによって登録された処理が実行される。

```javascript
var d = new Date();
$.when(d.getHours(), d.getMinutes()).done(function(h, m){
 $('div'), {text: h + '時' + m + '分です'}).appendTo(document.body);
});
// <div>15時10分です</div>
```
以上のような例のように、引数のオブジェクトが、doneで登録される関数の引数に設定されている。

```javascript
$.each(['red', 'blue'], function(i, name){
 $('div'), {width:100, height: 100, css: {backgroundColor: name}}
 .appendTo(document.body).hide();
});

// 追加した要素を表示させ、両方表示されたらテキストを追加
$.when($('div:first').show(3000), $('div:last').show(300))
.done(function(){$('div').text('jQuery'); });
```
$.whenの引数がDeferredオブジェクト、Promiseオブジェクトのときは、それぞれの状態がすべて`resolved`に移行していれば、whenに続くdoneで登録された処理が実行される。一方で、引数の中で、どれか一つでも`rejected`に移行した場合は、failで登録された処理が実行される。


`progress`メソッドも続けて実行でき、登録された関数の引数には、
whenメソッドの引数に設定された、Deferredオブジェクト、Promiseオブジェクトが
`notify`を実行したときの引数が
関数の引数に設定される。
元のオブジェクトの引数が複数の場合、配列で一つの引数として渡される。

#####Deferredオブジェクトに隠しdone/failの追加

$.Deferredの引数に、
生成されたDeferredオブジェクトを引数とする関数を
設定し、そこで引数の関数の引数にdoneやfailを実行すると、
元の生成されたDeferredオブジェクトに処理を追加済みにすることができる。

#### $.Callbacks

`$.Callbacks`はCallbacksオブジェクトを生成するメソッド。
`Callbacksオブジェクト`
先にコールバック関数を登録しておき、それを引数を変えつつ何度も実行したり、
先に引数を登録しておいて、それらを用いて、コールバック関数を実行したりすることができる
仕組みを持ったオブジェクト。
Deferredオブジェクトの処理キューなどに利用されている。
Callbacksオブジェクトのメソッドは、返り値がBooleanでないものなら、メソッドチェーンによって連続に実行できる。

```javascript
var fn = function(){
 var s = $.map(arguments, function(arg){return arg.toString(); }).join();
 $('<div>', {text: s}).appendTo(document.body);
};

var callbacks = $.Callbacks(); //Callbacksオブジェクト生成
callbacks.add(fn); // 関数の登録

// 引数を変えて登録した関数を実行。
callbacks.fire('A','B','C'); //ABC
callbacks.fire('D','E','F'); //DEF

```
```javascript
callbacks.add(fn1, fn2); //複数の引数で登録
callbacks.add([fn3, fn4]); //配列で登録
callbacks.remove(fn1) //関数の削除
callbacks.remove(fn2, fn3, fn4); //複数の関数の削除
```

Callbacksオブジェクト生成時のメソッドの引数としてフラグ名を文字列で渡すことで、
生成するCallbacksオブジェクトにフラグを設定することができる。

```javascript
var callbacks = $.Callbacks('once');
var callbacks = $.Callbacks('once memory')　//空白で列挙できる。
```

フラグは以下のとおりである。
`once` fireの実行完了後、登録された関数は削除される。
`unique`　同じ関数は登録されない。
`stopOnFalse`　戻り値がFalseの場合、それ以降関数を実行しない。
`memory`　登録された関数や、実行時の引数をオブジェクトに記憶する。