質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.38%

【JavaScript】デリゲートを理解したい

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 3,398

k499778

score 542

現在JavaScriptの実装をしているのですが、
運用上HTML上でonClick属性を設定しているところを、デリゲートさせて各場所で呼び出すようにしなければなりません。

ただデリゲートは初めて聞いた言葉で調べているのですがいまいち理解できていません。

以下のサイトを拝見しました。
http://blog.webcreativepark.net/2013/12/01-215447.html
http://blog.jnito.com/entry/20110706/1309901221

「メソッドを変数のようにして使うもの」や
「先祖要素にクリックイベントハンドラを登録することで、パブリングの防ぎ、負荷を少なくする方法」
というイメージを持ちました。

しかし、実際に「『デリゲートさせて』各場所で呼び出す」というのはどういうところにポイントを置いて書いたらいいのかがわかりません。

先祖要素にクリックイベントハンドラを登録して、実行したい要素を引数に入れるようにすればいいのか、
あるいはカプセル化?変数のようにメソッドを定義した書き方をすればいいのか、など推測を立てているのですが、まだ掴みきれていません。

もしお答えいただける方がいれば教えていただけると助かります。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

個人的にはデリゲートの概念は理解しなくても問題ないと考えています。
jQuery#on と DOM Events のイベントバブリングだけを理解すれば十分に事足ります。

<div id="parent">
  parent
  <p id="child">child</p>
</div>

<script type="text/javascript">
'use stirct';
jQuery('#parent').on('click', '#child', function (event) {
  console.log('jQuery: ' + this.id);                // "jQuery: child"
  console.log('jQuery: ' + event.currentTarget.id); // "jQuery: child"
});

document.getElementById('parent').addEventListener('click', function handleClick (event) {
  var target = event.target,
      id = target.id;

  while (id !== 'parent' && id !== 'child') {
    target = target.parentNode;
    id = target.id
  }

  if (id !== 'child') {
    return;
  }

  console.log('DOM: ' + target.id);              // "DOM: child"
  console.log('DOM: ' + this.id);                // "DOM: parent"
  console.log('DOM: ' + event.currentTarget.id); // "DOM: parent"
}, false);
</script>
  • イベント定義しているのは #parent なので #child は動的に削除→生成し直してもイベントを再定義する必要はありません
  • イベント定義しているのは #parent ですが、イベントハンドラ関数内では #child にイベント定義しているかのように振る舞います(this 値や event.currentTarget を書き換えます)

ちなみに、jQuery#on(events, handler) はイベントバブリングを利用している為、バブリングしないイベントタイプには適用できません。
jQuery はキャプチャリングフェーズに対応していない為、上位ノードで監視可能なイベントタイプに制限があります。

Re: k499778 さん

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/06/01 05:55 編集

    返答ありがとうございます。

    となると
    >jQuery('#parent').on('click', '#child', function (event) {
    の「jQuery('#parent')」の部分は
    ルートノードにする必要はないのかな?
    という疑問を持ちました。

    ご提示下さったコードは先祖要素がparentに当たるためいいと思うのですが、普段コーディングの際はルートノードがdocumentに当たるため、セレクタ部分をどうすればいいのか迷ってしまうのです。

    もしその疑問を解決いただけるようであればお答えいただけると嬉しいです。

    キャンセル

  • 2016/06/01 11:00 編集

    ルートノード(document)でも構いませんが、そうすると常にコード記入順で発火するので順序制御が面倒になると思います。

    jQuery(document.body).on('click', '#parent', handleClick); // 2番目
    jQuery('#paremt').on('click', '#child', handleClick); // 1番目

    jQuery(document).on('click', '#parent', handleClick); // 1番目
    jQuery(document).on('click', '#child', handleClick); // 2番目

    バブリングは子要素から親要素へ順番に発火する為、「#child -> #parent -> document.body -> document.documentElement -> document -> window」の順に発火するわけですが、常に document を指定すると入力順で発火します。
    http://www2u.biglobe.ne.jp/~oz-07ams/2003/Events3/xml-source-20031107-ja.xml#Events-flow
    ちなみに、document を指定すると DOMContentLoaded を待たなくていい利点はあります。

    キャンセル

  • 2016/06/01 12:16

    返答ありがとうございます。
    documentにしてもいいが、順序制御が面倒になるのですね。ただメリットもあるが。

    スッキリしました。
    わからないところは自分で調べて理解を深めます。

    長らく相談に乗って頂きありがとうございました。

    キャンセル

+2

delegateは「委譲」という意味で使われています。

「html上、もしくはイベントハンドラ上に処理を書かず、一定のオブジェクトに集約せよ」という指示ではないでしょうか?

例えば、

<button onclick="javascript:alert('委譲を全く使わないパターン');">Click me</button>


となっているところを

<button class="awesome-button">Click me</button>
$(function(){
  $('.awesome-button').click(function(){
    alert('clicked!');
  });
});


と書くことができます。HTML上にjavascriptコードを書かず、javascriptの処理はすべてjs内に書かれているので委譲を使わない場合よりも保守性があがります。
さらに、alert('clicked!')という処理を使いまわしたいならば

<button class="awesome-button">Click me</button>
<button class="newly-added-button">Click me</button>
$(function(){
  $('.awesome-button').click(function(){
    AlertUtil.doAlert('clicked!');
  });
  $('.newly-added-button').click(function(){
    AlertUtil.doAlert('This is New Button!');
  });
});

var AlertUtil={
  doAlert:function(msg){
     alert(msg);
  }
}


と掛けます。この場合、処理を行うのはAlertUtilであり、HTMLとイベント部分の処理は必要な引数だけを渡して処理をAlertUtilに委譲しています。
適切に委譲を使うことで、コードの保守性と再利用性を高めることができます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/31 23:13

    回答有り難うございます。

    呼び出し方はまさにその通りで一つのオブジェクトにまとめたものを呼び出して使うといった形でした。
    確かにコードの保守性と再利用性が上がりますね。
    わかりやすい説明のおかげです。ありがとうございます。

    「保守性、再利用性をあげるために一定のオブジェクトに集約する」と覚えておきます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.38%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る