Web技術勉強会                                        2011/07/23       Ryuichi TANAKA/@mapserver2007/summer-lights.jp         Ja...
これまでの内容JavaScriptのプロトタイプベースOOPライブラリ「mix.js」を開発を開始mix.jsの初期バージョン完成 バグあり。IEで動かない。バグ修正版mix.jsをリリース バグなし、IEでも動作。mix.js用ライブラリの開...
順調に育ってます開発から約2ヶ月。mix.js本体:213行 コメント、改行のみの行を含んでいるので実質190行くらい。mix.modules.js:743行 モジュール群。実質680行くらい。 Utils、Cache、Cookie、Http、...
ライブラリ開発でレベルアップこれまで触ったことのない深い知識が必要 プロトタイプチェーンのつなぎ替え クロージャ連発 厳密なエラー処理 テストこのライブラリ開発でかなり詳しくなれた、と自負。 JavaScriptに関しては中級者以上の実力がある...
ライブラリ開発は大変使う側から、使わせる側へIEで動かすことが特に大変 Chromeでは動くが、IEで動かないことはざら。だが、IEを簡単 に切り捨てることは負けを認めたことになる。テストがないと本当に死ねる テストをつねに通る状態にしておかな...
閑話休題ここから本題
今回の内容まずはこのコードをみてほしい。 Child.java    package jp.sample;    public class Child extends Parent {        public void caller() {...
今回の内容 Parent.java   package jp.sample;   public class Parent extends GrandParent {       public void caller() {           ...
今回の内容 Parent.java   package jp.sample;   public class GrandParent {       public void caller() {           name(); // これがど...
これを実行するとTest.java    package jp.sample;    public class Test {        public static void main(String[] args) {            ...
クラス図だとこんな      手順:      ・Childをインスタンス化      ・Child#callerを実行する。      ・Child#callerはParent#calerを呼び出す      ・Parent#callerはG...
答え答え。     $ > java Test     $ > name is childだからどうした、Javaじゃねえか!はい。でも、なんで「name is grand parent」じゃないのか。なんとなく不思議に思わないかい?
レシーバを意識してみる      child.super()super().caller()               イメージとしてはこんな感じになる。               (あくまでイメージ)               レシーバ...
だが、JavaScriptだとこうはならないJavaScriptで同じことをやると…          child.super().super().caller()          ↓          parent.super().call...
call, applyを使うと同じことはできる同じことは実はできる        child.super().super().caller()        ↓        super.apply(child)        ↓       ...
call, applyを使うと同じことはできるcall, applyは外部のオブジェクトを第一引数のオブジェクトとして呼び出すことができる神メソッド。 callとapplyの違いは第二引数で渡す引数の形式の違い。 callは個別に渡す(いくつで...
ここでmix.jsの話にようやく入るmix.jsでもまったく同じことが起きる回避方法も全く同じで、call, applyを使うが、これはない!!!なぜか。継承するたびに、レシーバを子供に戻す作業が毎回発生する。つまり、mix.jsを使う開発者に...
要するに今回の内容は親メソッドでthisを使っている場合、自動的にcall, applyをラップしてあげるよ、という実装の話。動作イメージ var Psp = Module.create({     name “psp”,     getNam...
とりあえずなにも考えずに実装これまでは親を「parent」プロパティで参照していた obj.parent.getName();parentを挙動を変えて実装してみた。が、失敗。 常に子をレシーバにして呼び出すことはできたが、既存の処理が 正常に...
parentと__parent__ あらたに「__parent__」を定義。  parentは「外部用親参照プロパティ」と定義  __parent__は「内部用親参照プロパティ」と定義 parent経由で親を参照するとレシーバは常に子になる _...
実装の肝実装の肝はどうやってレシーバを子に変換するか。parentに継承したモジュールのメソッドをチェーンさせるときに、メソッドをfor-inでバラして、メソッドをフックする。   // これまではだいたいこんな感じ   for (var pr...
実装の肝    function hook(self, f) {        return funciton() {            f.apply(self, arguments);        };    }applyを使ってレシ...
この機能によって得られる物同じような画面がある場合、ほとんどの処理を委譲できるためコード量を大幅に削減可能 処理が似ているけどちょっとだけ違う場合  オーバーライドが可能なので加工処理などを行える 処理が全く同じ場合  サブモジュール(サブクラ...
まとめmix.jsに内部親参照用プロパティ「__parent__」、外部親参照用プロパティ「parent」を実装 コードの重複を排除できるようになった オーバーライドを自然にできるようになった今後は 実装はほぼ終了 mix.js用モジュールはつ...
Upcoming SlideShare
Loading in...5
×

Web技術勉強会 20110723

1,225

Published on

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,225
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
1
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Web技術勉強会 20110723

  1. 1. Web技術勉強会 2011/07/23 Ryuichi TANAKA/@mapserver2007/summer-lights.jp JavaScriptでプロトタイプベースオブジェクト指向プログラミング~続々・親子関係を維持してクラスを使わないオブジェクト指向プログラミング手法~
  2. 2. これまでの内容JavaScriptのプロトタイプベースOOPライブラリ「mix.js」を開発を開始mix.jsの初期バージョン完成 バグあり。IEで動かない。バグ修正版mix.jsをリリース バグなし、IEでも動作。mix.js用ライブラリの開発 前回一部紹介。
  3. 3. 順調に育ってます開発から約2ヶ月。mix.js本体:213行 コメント、改行のみの行を含んでいるので実質190行くらい。mix.modules.js:743行 モジュール群。実質680行くらい。 Utils、Cache、Cookie、Http、Designアプリケーションにも現在適用中(RankForce3, Rails製のアプリ)。
  4. 4. ライブラリ開発でレベルアップこれまで触ったことのない深い知識が必要 プロトタイプチェーンのつなぎ替え クロージャ連発 厳密なエラー処理 テストこのライブラリ開発でかなり詳しくなれた、と自負。 JavaScriptに関しては中級者以上の実力があると、勝手に自負し てるが、このライブラリは我ながらかなり使えると思ってる。な ので、これからどんどん使っていく予定。
  5. 5. ライブラリ開発は大変使う側から、使わせる側へIEで動かすことが特に大変 Chromeでは動くが、IEで動かないことはざら。だが、IEを簡単 に切り捨てることは負けを認めたことになる。テストがないと本当に死ねる テストをつねに通る状態にしておかないと、機能追加や仕様変更 で地獄を見る。 通常のアプリと違って、影響範囲がほぼコード全域に及ぶ。した がって、使い捨てのテストコードで都度確認するわけにはいかな い。常に過去に正しく動いていて、かつ、変更後も正しく動くこ とを保証し続けないといけない。 テストがなかったら途中で投げてたかも。 おかげで、機能変更がまったく怖くない。
  6. 6. 閑話休題ここから本題
  7. 7. 今回の内容まずはこのコードをみてほしい。 Child.java package jp.sample; public class Child extends Parent { public void caller() { super.caller(); } public void name() { System.out.println("name is child"); } }
  8. 8. 今回の内容 Parent.java package jp.sample; public class Parent extends GrandParent { public void caller() { super.caller(); } public void name() { System.out.println("name is parent"); } }
  9. 9. 今回の内容 Parent.java package jp.sample; public class GrandParent { public void caller() { name(); // これがどこを指すか? } public void name() { System.out.println("name is grand parent"); } }
  10. 10. これを実行するとTest.java package jp.sample; public class Test { public static void main(String[] args) { Child child = new Child(); child.caller(); } }問題: これを実行すると、何と表示されるでしょう?
  11. 11. クラス図だとこんな 手順: ・Childをインスタンス化 ・Child#callerを実行する。 ・Child#callerはParent#calerを呼び出す ・Parent#callerはGrandParent#callerを呼び出す ・GrapndParent#callerはGrandParent#nameを 呼び出す。 GrandParent#nameはどこを指す?
  12. 12. 答え答え。 $ > java Test $ > name is childだからどうした、Javaじゃねえか!はい。でも、なんで「name is grand parent」じゃないのか。なんとなく不思議に思わないかい?
  13. 13. レシーバを意識してみる child.super()super().caller() イメージとしてはこんな感じになる。 (あくまでイメージ) レシーバは常にchildになるので、 GrandParent#callerが呼ばれても childとして呼ばれることになる。 したがってname()はChild#name。 ちなみにレシーバはRuby用語。 child.super().caller()
  14. 14. だが、JavaScriptだとこうはならないJavaScriptで同じことをやると… child.super().super().caller() ↓ parent.super().caller() ↓ grandparent.caller() 継承をうまいことやってあげたとする。 Javaと同じ呼び出し方をしても、 親を呼び出した時点でレシーバが親のレシー バに変化してしまう。 最終的にはGrandParent#callerは Grandparent#nameを実行する。 ※というかこういう継承関係をとれるライブラリがほとんど ないわけだが。
  15. 15. call, applyを使うと同じことはできる同じことは実はできる child.super().super().caller() ↓ super.apply(child) ↓ child.super().caller() ↓ super.apply(child) ↓ caller.apply(child) ↓ child.caller()
  16. 16. call, applyを使うと同じことはできるcall, applyは外部のオブジェクトを第一引数のオブジェクトとして呼び出すことができる神メソッド。 callとapplyの違いは第二引数で渡す引数の形式の違い。 callは個別に渡す(いくつでも渡せる) applyは配列で渡せる(1つだけ)。argumentsをそのまま渡すと きはこっちを使う。つまり、第一引数のオブジェクトをレシーバとして指定できる。指定しない場合は呼び出し先のオブジェクト。これを利用するとさっきJavaでやったことと同じになる。
  17. 17. ここでmix.jsの話にようやく入るmix.jsでもまったく同じことが起きる回避方法も全く同じで、call, applyを使うが、これはない!!!なぜか。継承するたびに、レシーバを子供に戻す作業が毎回発生する。つまり、mix.jsを使う開発者に余計な手間をかけさせることになる。普通、Javaなどと同じ挙動になるだろうと思うはず。でそのとおりにならないのでバグになる、と。ライブラリとは、こういうことを全部よしなにやってあげるためにあるわけで。故にこれはない。
  18. 18. 要するに今回の内容は親メソッドでthisを使っている場合、自動的にcall, applyをラップしてあげるよ、という実装の話。動作イメージ var Psp = Module.create({ name “psp”, getName: function() { return this.name; } }); var PsVita = Module.create({ name: “psvita”, getName: function() { return this.parent.name; } }); var obj = PsVita.mix(Psp); obj.getName(); // psvita
  19. 19. とりあえずなにも考えずに実装これまでは親を「parent」プロパティで参照していた obj.parent.getName();parentを挙動を変えて実装してみた。が、失敗。 常に子をレシーバにして呼び出すことはできたが、既存の処理が 正常に動作しなくなった。 具体的にはhasメソッド。テストが軒並みこけるように。一旦白紙に戻し方針転換。いっそ、既存の処理に影響がでないようにプロパティを新たに追加することにした。
  20. 20. parentと__parent__ あらたに「__parent__」を定義。 parentは「外部用親参照プロパティ」と定義 __parent__は「内部用親参照プロパティ」と定義 parent経由で親を参照するとレシーバは常に子になる __parent__経由で親を参照するとレシーバは現在参照して いるオブジェクト(モジュール)。 ルール上、__parent__の仕様は非推奨とした。 __parent__はあくまで「内部」で使う目的で定義したため 「__」をつけているのは通常のプロパティとは違う、という意味 を含めている。 mix.jsの作り上、特定のプロパティを非公開(private)にはできな いので、参照自体は可能。
  21. 21. 実装の肝実装の肝はどうやってレシーバを子に変換するか。parentに継承したモジュールのメソッドをチェーンさせるときに、メソッドをfor-inでバラして、メソッドをフックする。 // これまではだいたいこんな感じ for (var prop in parent) { child[prop] = parent[prop]; } // 今はこんな感じ for (var prop in parent) { child[prop] = hook(child, parent[prop]); }
  22. 22. 実装の肝 function hook(self, f) { return funciton() { f.apply(self, arguments); }; }applyを使ってレシーバを子供にしつつ、処理自体は委譲してあげる
  23. 23. この機能によって得られる物同じような画面がある場合、ほとんどの処理を委譲できるためコード量を大幅に削減可能 処理が似ているけどちょっとだけ違う場合 オーバーライドが可能なので加工処理などを行える 処理が全く同じ場合 サブモジュール(サブクラスに相当)にメソッド定義しなくてすむ=そ のままスーパーモジュール(スーパークラスに相当)を「自動的に」 コールするため不要この機能によって一般的なOOPと同じ利点が得られる
  24. 24. まとめmix.jsに内部親参照用プロパティ「__parent__」、外部親参照用プロパティ「parent」を実装 コードの重複を排除できるようになった オーバーライドを自然にできるようになった今後は 実装はほぼ終了 mix.js用モジュールはつくるかもしれない Webアプリケーションに適用して評価する
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×