SlideShare a Scribd company logo
Web技術勉強会
                                        2011/07/23
       Ryuichi TANAKA/@mapserver2007/summer-lights.jp

         JavaScriptでプロトタイプベースオブジェクト指向プログラミング
~続々・親子関係を維持してクラスを使わないオブジェクト指向プログラミング手法~
これまでの内容
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、Design
アプリケーションにも現在適用中(RankForce3, Rails製の
アプリ)。
ライブラリ開発でレベルアップ
これまで触ったことのない深い知識が必要
 プロトタイプチェーンのつなぎ替え
 クロージャ連発
 厳密なエラー処理
 テスト
このライブラリ開発でかなり詳しくなれた、と自負。
 JavaScriptに関しては中級者以上の実力があると、勝手に自負し
 てるが、このライブラリは我ながらかなり使えると思ってる。な
 ので、これからどんどん使っていく予定。
ライブラリ開発は大変
使う側から、使わせる側へ
IEで動かすことが特に大変
 Chromeでは動くが、IEで動かないことはざら。だが、IEを簡単
 に切り捨てることは負けを認めたことになる。
テストがないと本当に死ねる
 テストをつねに通る状態にしておかないと、機能追加や仕様変更
 で地獄を見る。
 通常のアプリと違って、影響範囲がほぼコード全域に及ぶ。した
 がって、使い捨てのテストコードで都度確認するわけにはいかな
 い。常に過去に正しく動いていて、かつ、変更後も正しく動くこ
 とを保証し続けないといけない。
 テストがなかったら途中で投げてたかも。
 おかげで、機能変更がまったく怖くない。
閑話休題
ここから本題
今回の内容
まずはこのコードをみてほしい。
 Child.java
    package jp.sample;

    public class Child extends Parent {
        public void caller() {
            super.caller();
        }

         public void name() {
             System.out.println("name is child");
         }
    }
今回の内容
 Parent.java
   package jp.sample;

   public class Parent extends GrandParent {
       public void caller() {
           super.caller();
       }

        public void name() {
            System.out.println("name is parent");
        }
   }
今回の内容
 Parent.java
   package jp.sample;

   public class GrandParent {
       public void caller() {
           name(); // これがどこを指すか?
       }

        public void name() {
            System.out.println("name is grand parent");
        }
   }
これを実行すると
Test.java
    package jp.sample;

    public class Test {
        public static void main(String[] args) {
            Child child = new Child();
            child.caller();
        }
    }




問題:
 これを実行すると、何と表示されるでしょう?
クラス図だとこんな

      手順:
      ・Childをインスタンス化
      ・Child#callerを実行する。
      ・Child#callerはParent#calerを呼び出す
      ・Parent#callerはGrandParent#callerを呼び出す
      ・GrapndParent#callerはGrandParent#nameを
       呼び出す。

      GrandParent#nameはどこを指す?
答え
答え。
     $ > java Test
     $ > name is child

だからどうした、Javaじゃねえか!
はい。でも、なんで「name is grand parent」じゃない
のか。なんとなく不思議に思わないかい?
レシーバを意識してみる

      child.super()super().caller()

               イメージとしてはこんな感じになる。
               (あくまでイメージ)

               レシーバは常にchildになるので、
               GrandParent#callerが呼ばれても
               childとして呼ばれることになる。
               したがってname()はChild#name。

               ちなみにレシーバはRuby用語。

    child.super().caller()
だが、JavaScriptだとこうはならない
JavaScriptで同じことをやると…

          child.super().super().caller()
          ↓
          parent.super().caller()
          ↓
          grandparent.caller()


           継承をうまいことやってあげたとする。
           Javaと同じ呼び出し方をしても、
           親を呼び出した時点でレシーバが親のレシー
           バに変化してしまう。
           最終的にはGrandParent#callerは
           Grandparent#nameを実行する。

       ※というかこういう継承関係をとれるライブラリがほとんど
        ないわけだが。
call, applyを使うと同じことはできる
同じことは実はできる

        child.super().super().caller()
        ↓
        super.apply(child)
        ↓
        child.super().caller()
        ↓
        super.apply(child)
        ↓
        caller.apply(child)
        ↓
        child.caller()
call, applyを使うと同じことはできる
call, applyは外部のオブジェクトを第一引数のオブジェク
トとして呼び出すことができる神メソッド。
 callとapplyの違いは第二引数で渡す引数の形式の違い。
 callは個別に渡す(いくつでも渡せる)
 applyは配列で渡せる(1つだけ)。argumentsをそのまま渡すと
 きはこっちを使う。
つまり、第一引数のオブジェクトをレシーバとして指定で
きる。指定しない場合は呼び出し先のオブジェクト。
これを利用するとさっきJavaでやったことと同じになる。
ここでmix.jsの話にようやく入る
mix.jsでもまったく同じことが起きる
回避方法も全く同じで、call, applyを使う



が、これはない!!!
なぜか。継承するたびに、レシーバを子供に戻す作業が毎
回発生する。
つまり、mix.jsを使う開発者に余計な手間をかけさせるこ
とになる。
普通、Javaなどと同じ挙動になるだろうと思うはず。でそ
のとおりにならないのでバグになる、と。
ライブラリとは、こういうことを全部よしなにやってあげ
るためにあるわけで。故にこれはない。
要するに今回の内容は
親メソッドで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
とりあえずなにも考えずに実装
これまでは親を「parent」プロパティで参照していた
 obj.parent.getName();
parentを挙動を変えて実装してみた。
が、失敗。
 常に子をレシーバにして呼び出すことはできたが、既存の処理が
 正常に動作しなくなった。
 具体的にはhasメソッド。テストが軒並みこけるように。
一旦白紙に戻し方針転換。
いっそ、既存の処理に影響がでないようにプロパティを新
たに追加することにした。
parentと__parent__
 あらたに「__parent__」を定義。
  parentは「外部用親参照プロパティ」と定義
  __parent__は「内部用親参照プロパティ」と定義
 parent経由で親を参照するとレシーバは常に子になる
 __parent__経由で親を参照するとレシーバは現在参照して
 いるオブジェクト(モジュール)。
 ルール上、__parent__の仕様は非推奨とした。
  __parent__はあくまで「内部」で使う目的で定義したため
  「__」をつけているのは通常のプロパティとは違う、という意味
  を含めている。
  mix.jsの作り上、特定のプロパティを非公開(private)にはできな
  いので、参照自体は可能。
実装の肝
実装の肝はどうやってレシーバを子に変換するか。
parentに継承したモジュールのメソッドをチェーンさせる
ときに、メソッドをfor-inでバラして、メソッドをフック
する。
   // これまではだいたいこんな感じ
   for (var prop in parent) {
       child[prop] = parent[prop];
   }

   // 今はこんな感じ
   for (var prop in parent) {
       child[prop] = hook(child, parent[prop]);
   }
実装の肝
    function hook(self, f) {
        return funciton() {
            f.apply(self, arguments);
        };
    }

applyを使ってレシーバを子供にしつつ、処理自体は委譲
してあげる
この機能によって得られる物
同じような画面がある場合、ほとんどの処理を委譲できる
ためコード量を大幅に削減可能
 処理が似ているけどちょっとだけ違う場合
  オーバーライドが可能なので加工処理などを行える
 処理が全く同じ場合
  サブモジュール(サブクラスに相当)にメソッド定義しなくてすむ=そ
  のままスーパーモジュール(スーパークラスに相当)を「自動的に」
  コールするため不要
この機能によって一般的なOOPと同じ利点が得られる
まとめ
mix.jsに内部親参照用プロパティ「__parent__」、外部親
参照用プロパティ「parent」を実装
 コードの重複を排除できるようになった
 オーバーライドを自然にできるようになった
今後は
 実装はほぼ終了
 mix.js用モジュールはつくるかもしれない
 Webアプリケーションに適用して評価する

More Related Content

PDF
Javascripでオブジェクト指向
PDF
JavaScriptの落とし穴
PDF
最強オブジェクト指向言語 JavaScript 再入門!
PPT
[A 3]SSJSでも使える!Javascriptでオブジェクト指向プログラミング入門
PDF
JavaScript超入門 基礎
PDF
JavaScript入門-基礎編
PDF
20120327 phpstudy58-phake
PPTX
Perlでちょいモテデザインパターン
Javascripでオブジェクト指向
JavaScriptの落とし穴
最強オブジェクト指向言語 JavaScript 再入門!
[A 3]SSJSでも使える!Javascriptでオブジェクト指向プログラミング入門
JavaScript超入門 基礎
JavaScript入門-基礎編
20120327 phpstudy58-phake
Perlでちょいモテデザインパターン

Viewers also liked (9)

PDF
Web技術勉強会 第37回
PDF
Web技術勉強会 20110611
PDF
Web技術勉強会 20130525 - Google Cloud Messaging入門
PDF
Web技術勉強会 20120728
PDF
Web技術勉強会 20111112
PDF
Web技術勉強会 20120609
PDF
Web技術勉強会 20120114 - JenkinsでJava/PHP/Ruby/JavaScriptをビルドする
PDF
WebSocketでリアルタイム処理をする
PDF
WebSocketのキホン
Web技術勉強会 第37回
Web技術勉強会 20110611
Web技術勉強会 20130525 - Google Cloud Messaging入門
Web技術勉強会 20120728
Web技術勉強会 20111112
Web技術勉強会 20120609
Web技術勉強会 20120114 - JenkinsでJava/PHP/Ruby/JavaScriptをビルドする
WebSocketでリアルタイム処理をする
WebSocketのキホン
Ad

Similar to Web技術勉強会 20110723 (20)

PDF
Web技術勉強会 20110528
KEY
いまさらJavaScript
PDF
ECMAScript没proposal追悼式
PDF
JavaScript.Next
PDF
PHPとJavaScriptにおけるオブジェクト指向を比較する
PDF
ちょっと詳しくJavaScript 特別編【悪霊の神々】
PDF
Javaセキュアコーディングセミナー東京第1回 講義
PDF
JavaScriptおよびXPages Vote技術解説
PDF
LITメンター研修_Android0212
PDF
ちょっと詳しくJavaScript 第3回【prototype】
PDF
JavaScript入門
PPTX
Javascriptのデザインパターン【勉強会資料】
PPTX
PDF
【LiT Leaders】Android0309
PDF
Template method #dezapatan
PDF
JavaScript.Next Returns
PPT
オブジェクト指向入門7
PDF
JSクラス定義
KEY
Inside frogc in Dart
PDF
「エクストリームエンジニアへの道(Swift編)」
Web技術勉強会 20110528
いまさらJavaScript
ECMAScript没proposal追悼式
JavaScript.Next
PHPとJavaScriptにおけるオブジェクト指向を比較する
ちょっと詳しくJavaScript 特別編【悪霊の神々】
Javaセキュアコーディングセミナー東京第1回 講義
JavaScriptおよびXPages Vote技術解説
LITメンター研修_Android0212
ちょっと詳しくJavaScript 第3回【prototype】
JavaScript入門
Javascriptのデザインパターン【勉強会資料】
【LiT Leaders】Android0309
Template method #dezapatan
JavaScript.Next Returns
オブジェクト指向入門7
JSクラス定義
Inside frogc in Dart
「エクストリームエンジニアへの道(Swift編)」
Ad

More from 龍一 田中 (20)

PDF
Web技術勉強会 20110514
PDF
Web技術勉強会 20100925
PDF
Web技術勉強会 20100424
PDF
Web技術勉強会 第38回
PDF
Web技術勉強会 第34回
PDF
Web技術勉強会 第33回
PDF
Web技術勉強会 第31回
PDF
Web技術勉強会 第30回
PDF
Web技術勉強会 第29回
PDF
Web技術勉強会 第28回
PDF
Web技術勉強会 第26回
PDF
Web技術勉強会 第25回
PDF
Web技術勉強会23回目
PDF
Web技術勉強会 第19回
PDF
Web技術勉強会 第18回
PDF
Web技術勉強会12回目
PDF
Web技術勉強会11回目
PDF
Web技術勉強会10回目(Slideshare用)
PDF
Web技術勉強会9回目2(Slideshare用)
PDF
Web技術勉強会9回目(Slideshare用)
Web技術勉強会 20110514
Web技術勉強会 20100925
Web技術勉強会 20100424
Web技術勉強会 第38回
Web技術勉強会 第34回
Web技術勉強会 第33回
Web技術勉強会 第31回
Web技術勉強会 第30回
Web技術勉強会 第29回
Web技術勉強会 第28回
Web技術勉強会 第26回
Web技術勉強会 第25回
Web技術勉強会23回目
Web技術勉強会 第19回
Web技術勉強会 第18回
Web技術勉強会12回目
Web技術勉強会11回目
Web技術勉強会10回目(Slideshare用)
Web技術勉強会9回目2(Slideshare用)
Web技術勉強会9回目(Slideshare用)

Web技術勉強会 20110723