@ledsun blog

無味の味は佳境に入らざればすなわち知れず

RubyのdelegateみたいなことをJavaScriptでやる

Rubydelegate

Rubyにはdelegateというメソッドがあります。

docs.ruby-lang.org

あるクラスのメソッドを、依存するインスタンスに委譲するメソッドです。 次のように使います。

delegate [:first, :last] => :@arr

ぱっと見不思議ですが、ハッシュ { [:first, :last] => :@arr } が引数の関数呼び出しです。 firstメソッドとlastメソッドを@arrインスタンスに委譲しています。

JavaScriptの実装

似たようなことをJavaScriptでやりたいなと思いました。

次のように実装しました。

function forwardMethods(self, getTargetFunction, methods) {
  for (const method of methods) {
    self[method] = (...args) => {
      const target = getTargetFunction()
      console.assert(target[method], `No ${method} method to forward`, target)

      return target[method].apply(target, args)
    }
  }
}

使い方は次の通りです。

forwardMethods(this, () => this._clipBoard, [
  'copyEntities',
  'cutEntities',
  'pasteEntities'
])

第一引数がthisなのは、クラスのコンストラクタ関数の中で使う想定だからです。 オブジェクトを指定すれば良いので、コンストラクタの外でも使えます。

第二引数がコールバック関数なのは、委譲先を動的に解決したかったからです。

関数名にはdelegateではなくforwardを使いました。 JavaScript界には、次のようにたくさんのdelegateがいて紛らわしいからです。

参考

Mixins, Forwarding, and Delegation in JavaScript

このブログを眺めながら、APIとか実装を考えました。

delega - npm

実装後に、npmなら似たようなパッケージがあるだろうと、探したnpmパッケージです。 APIが完全に一致していました。 まあまあ、汎用的なAPI設計ができていたようです。