委譲 - JavaScriptの個人的なメモ

委譲の意味を整理

JavaScriptでは4つの意味を持った委譲があります。まず、あいまいさを避けるため、ここで、それを整理してみましょう。

  1. オブジェクト指向プログラミング言語で使われている委譲
  2. プロトタイプチェインを使った委譲
  3. apllyメソッドやcallメソッドを使ったthisの委譲
  4. イベント委譲

ここでは、1の「オブジェクト指向プログラミング言語で使われている委譲」(以後、委譲と略す)の実装について、説明していきます。つまり、他のプログラミング言語を習得している方に向けたものです。個人的なメモですので、誤りがあるかもしれません。見つけたら、ご指摘ください。

サンプルのコード

さっそくですが、JavaScriptで委譲を実装してみましょう。
まず、二つのオブジェクト、aとsを用意して、オブジェクトsのhogeメソッドがaのhogeメソッドを参照するようにしてみます。以下のようにすれば、シンプルにできます。

function D() {
  this.a = 12;
  this.hoge = function() {
    return this.a;
  }
};

function F() {
  var a = new D();
  this.hoge = function() {
    return a.hoge();
  };
};

var s = new F();
s.hoge(); // 12を出力

s.hogeメソッドは、オブジェクトaのhogeメソッドを呼び出しています。
このように、処理を他のオブジェクトに任せると、機能の拡張ができます(注1)。

bindメソッド

thisの遅延束縛 (注2) をキャンセルするbindメソッドを使うと、さらに簡単に委譲ができるようになります。たとえば、上のコードをbindメソッドを使って、書き直してみましょう。

function D() {
  this.a = 12;
  this.hoge = function() {
    return this.a;
  }
};

function F() {
  var a = new D();
  this.hoge = a.hoge.bind(a); //bindメソッドによって、thisが第一引数のaに固定されるような、関数オブジェクトを返す
};

var s = new F();
s.hoge(); // 12

bindメソッドはthisとargumentsを固定することができるので、便利なメソッドです。thisの遅延束縛が面倒な人にぜひ、おすすめしたいです。

that = thisを使う

さらに、コンストラクタ関数 D にthat = thisを使うと、委譲と継承ができます。
委譲と継承の利点をまとめるために、ここでは比較として、両方のサンプルをコードとして書いておきます。Fが委譲で、F1が継承をしています。

function D() {
  var that = this;
  this.a = 12;
  this.hoge = function() {
    return that.a;
  };
};

function F() {
  var a = new D();
  this.hoge = a.hoge;       //Dに委譲
};

function F1() {
  D.apply(this, arguments); //Dを継承
};

var s = new F();
s.hoge(); // 12
s.a;      // undefined

var t = new F1();
t.hoge(); // 12
t.a;      // 12

s.hogeメソッドはD::hogeなのに対して、t.hogeメソッドはF1::hogeとなり、F1由来のメソッドです。

プロトタイプ

prototypeプロパティを使うと、より強力な委譲を行うことができます。ただし、オブジェクトの「継承」という意味合いが強いです。
以下のコードでは、dのaプロパティも受け継いでいます。

function F() {};

var d = new D();

F.prototype = d;

var s = new F();
s.hoge();  // 12
s.a;       // 12 d.aプロパティだということに注意

一部の処理だけではなくて、オブジェクトをまるごと継承しているイメージでかまいません。「委譲」と区別するために、冒頭では、2の「プロトタイプチェインを使った委譲」として別に分けています。
その他、ネットで調べると、いろいろな委譲を実現した手法に出会うのですが、長くなりそうな解説は他の記事に譲ります。

結論

  • 他のプログラミングと違って、JavaScriptでは、一口に委譲といってもいろいろあるよ
  • 他のオブジェクトに任せると、拡張したいときに楽

参考資料

注1 委譲については、「Delegation - Strategic Choice」を参照

http://d.hatena.ne.jp/asakichy/20090402/1238664387

注2 thisの遅延束縛 - JavaScriptの個人的なメモ (その3)

http://d.hatena.ne.jp/dhrname/20121026