25

Click here to load reader

defjs をひも解く

Embed Size (px)

Citation preview

Page 1: defjs をひも解く

def.js をひも解く~オレ標準 js 記法~

id:mooz

@stillpedant

Page 2: defjs をひも解く

自己紹介

• 名前

– mooz (Hatena, GitHub, …)

– stillpedant (Twitter, Google)

• 好きな言語

– Mozilla 系 JavaScript

• 作ったもの

– KeySnail (Emacs 版 Vimperator)

– MiSPLi (Lisp 処理系 in JavaScript)

– その他もろもろ

近影

詳しくは http://mooz.github.com/index-ja.html で

Page 3: defjs をひも解く

def.js

Page 4: defjs をひも解く

def.js

• http://github.com/tobeytailor/def.js

• Ruby に似た記法でクラス定義と継承が行える

Page 5: defjs をひも解く

サンプルコード

Page 6: defjs をひも解く

サンプルコード

!?

Page 7: defjs をひも解く

説明

• def (クラス名) (定義);

– クラス定義

– def ("Person") ({ … });

• def (クラス名) << 親クラス(定義);

– 親クラスを指定したクラス定義 (継承)

– def (“Ninja") << Person({ … });

• this._super();

– メソッド中から用いる

– 親クラスの同名メソッドを呼び出し

Page 8: defjs をひも解く

サンプルコード (再掲)

Page 9: defjs をひも解く

今回のスライドの目的

• def.js の挙動を理解する

• def (クラス名) (定義);

• def (クラス名) << 親クラス(定義);

• this._super();

Page 10: defjs をひも解く

def (クラス名) (定義);

Page 11: defjs をひも解く

def (クラス名) (定義);

• def 関数は関数 (deferred) を返す

• def(“Person”) とすると

– Person クラスが作成され (window.Person が定義される)

– 「定義 (props) を使って Person クラスを拡張する関数」が返る

• つまり def(“Person”)({ … }); とすると

– Person クラスが定義され, { … } を使ってそのクラスが拡張される

※ “拡張” : メソッドやプロパティを定義すること

Page 12: defjs をひも解く

def (クラス名) << 親クラス(定義);

Page 13: defjs をひも解く

def (クラス名) << 親クラス(定義);

• 前述の通り def 関数は関数 deferred を返す

• この関数には valueOf というプロパティが設定されている

• この valueOf がミソ

Page 14: defjs をひも解く

valueOf

• オブジェクトをプリミティブ値に変換する際に呼ばれる

• プリミティブ値が期待される場面にオブジェクトが出くわしたとき自動的に呼ばれる

Page 15: defjs をひも解く

valueOf の挙動

実行すると,

1. def(foo) called

2. def(bar) called

3. foo (valueOf)

4. bar (valueOf)

Page 16: defjs をひも解く

def (クラス名) << 親クラス(定義);

• def 関数は valueOf の設定された関数 deferred

を返す

• def (クラス名) << 親クラス(定義); とすると合計で 3 回関数が呼ばれる

def (クラス名)

親クラス(定義)

dererred.valueOf

(def の返り値)

Page 17: defjs をひも解く

def(“Ninja”) << Person({ … });

def(“Ninja”) << Person({ … }); としたとき……

deferred

def(“Ninja”)

1. Ninja クラスを作成2. deferred.valueOf を設定3. deferred を返す

Person({ … });

1. deferred の _super に Person を設定2. deferred の _props に { … } を設定

_super, _props を設定

deferred.valueOf

def(“Ninja”) の返した deferred に valueOf が設定されているので……

def.js のコンテキスト内でグローバル

1. deferred の _props を使い Ninja クラスを拡張2. deferred の _super を使い Ninja の親クラスを Person に設定

(Ninja に _superClass プロパティを設定する)

Page 18: defjs をひも解く

つまりは……

• A() 演算子 B() のとき

1. A()

2. B()

3. A の返したオブジェクトの valueOf

• という順番で呼ばれてくれれば何でも良い

• << である必要性は無い

– def(“Ninja”) >> Person({ … });

– def(“Ninja”) + Person({ … });

Page 19: defjs をひも解く

this._super();

Page 20: defjs をひも解く

_super();

• 関数の caller プロパティを使って _super の呼び出し元メソッドを取得.

• メソッドの _class プロパティによりクラスを取得

• クラスの _super プロパティにより親クラスを取得

• メソッドの _name プロパティによりメソッドの名前を取得し, 親クラスの持つ同名メソッドを呼ぶ

Page 21: defjs をひも解く

_super() の使う各プロパティ

• Klass.extend 時に追加– メソッドの _name

– メソッドの _class

• deferred.valueOf により追加

– クラスの _super

• JavaScript 標準

– arguments.callee• その関数自身

• JavaScript 非標準 (ほぼ全てのブラウザが実装)

– caller プロパティ• その関数を呼んだ関数

Page 22: defjs をひも解く

まとめ

Page 23: defjs をひも解く

まとめ

• def (クラス名) (定義);

– 関数を返す関数

• def (クラス名) << 親クラス(定義);

– valueOf

– << である必要なし

• this._super();

– arguments.callee.caller

Page 24: defjs をひも解く

演算子オーバーロード欲しい

Page 25: defjs をひも解く

資料

• def.js

– http://github.com/tobeytailor/def.js

• 日本語の解説コメントをつけたコード

– https://gist.github.com/2ac889f4b0276ddf9586

ご静聴ありがとうございました