• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Web技術勉強会 20110514
 

Web技術勉強会 20110514

on

  • 1,291 views

プロトタイプベースオブジェクト指向プログラミング(親子関係を維持した継承)

プロトタイプベースオブジェクト指向プログラミング(親子関係を維持した継承)

Statistics

Views

Total Views
1,291
Views on SlideShare
1,290
Embed Views
1

Actions

Likes
0
Downloads
8
Comments
0

1 Embed 1

https://twitter.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Web技術勉強会 20110514 Web技術勉強会 20110514 Presentation Transcript

    • Web技術勉強会 2011/05/14 Ryuichi TANAKA/@mapserver2007/summer-lights.jp JavaScriptでプロトタイプベースオブジェクト指向プログラミング~親子関係を維持してクラスを使わないオブジェクト指向プログラミング手法~
    • Introduction この違い、わかりますか? ① var Phone = { type: function() { return “basic phone”; } }; ② var Phone = function() {}; Phone.prototype = { type: function() { return “basic phone”; } };
    • Introduction 呼び出し方が違う ①:Phone.type(); ②:var phone = new Phone(); phone.type(); メモリ効率が違う ①:オブジェクトとして定義したときにメモリを確保 ②:インスタンスを生成したときにメモリを確保 形式が違う ①:オブジェクト ②:関数(クラス)
    • どちらを使うべきかオブジェクト指向プログラミングするなら② クラスを定義する var Phone = funciton() {}; メソッドを定義する Phone.prototype = { … }: Phone.prototype.type = function() { … }; 継承する Phone.type = new Telephone(); // 簡易な継承方法 インスタンス化 var obj = new Phone();他言語のOOPと比較的似ているいろいろ試行錯誤した結果、これがベスト
    • と、思ってた時期が先週まであった
    • さっきのやり方はベストではないと思い直した見直したきっかけ http://blog.tojiru.net/article/199670885.htmlやっぱりクラスではなくオブジェクトとして扱うのがベストなのではないか JavaScriptはプロトタイプベースのオブジェクト指向プログ ラミング言語 さっきのはクラスベース非効率だった わざわざオブジェクトをクラス(にみたてて)化、使うときに newで再度オブジェクト化しているどうすればよいか いずれにしてもクラス化する方法はベストではない GoodPartsにもnewはBadPartsであると明記されている JavaScriptパターンではモダンではない旨が明記されている オブジェクトのまま扱う方法がベストではないのか
    • こうすればよい(のではないか)実装目標 オブジェクトのまま扱う(クラス化しない) new禁止 感覚としてはモジュールのような感じ オブジェクトのまま継承する 親子関係を維持する http://blog.tojiru.net/article/199670885.htmlのやり方で は不十分。親子関係が消滅している。 Rubyっぽくしたい 関数で継承しないでメソッドで継承
    • 件のサイトについてhttp://blog.tojiru.net/article/199670885.html基本的にかなり参考になる(ブコメもすごい数) が、問題がある。かなり重大な。「継承」ではない 継承と言いつつ、プロパティを上書きしているため親子 関係は消滅。つまり、同じメソッド名は定義できない。個人的な美的感覚にマッチしていない 継承方法がちょっとカッコ悪い(関数で継承) これは別に悪くない。 継承順が逆 これはだめ
    • 件のサイトについて継承順について サイトではこうなっている var Dog = object(Animal, { name: “犬”, bowwow: function() { alert(“わんわん!”); } }); これは、extend(Animal, Dog); という意味。 英文にすると、Animal extend Dog 動物は犬を継承→??? つまり、逆でないとおかしい Dog extend Animal extend(Dog, Animal);これらの点を解消してあげればかなりよい方法が導けそう
    • 「JavaScriptらしさ」を損なわないでオブジェクト指向化美的感覚にマッチした実装 Dog.extend(Animal)みたいな継承方法親子関係を維持する プロトタイプチェーンを使う 親のメソッドを参照できるようにする var obj = Dog.extend(Animal); obj.parent.getName();複数の継承を許可 単一継承(ただし連鎖可能) var dog = Retriever.extend(Dog).extend(Animal); 多重継承(ただし後勝ち) var dog = Retriever.extend(Dog, Animal);
    • プロトタイプチェーンとはオブジェクトに存在するプロパティのひとつ参照しているオブジェクトがあればそのオブジェクトを指す 例:Array->ObjectObject.prototype === nullのときチェーンは終了 http://igeta.cocolog-nifty.com/blog/2007/04/prototype.html
    • prototypeと__proto__ __proto__プロパティはプロトタイプチェーンをた どるためのプロパティ prototypeプロパティは関数オブジェクトを拡張す るためのプロパティ __proto__はアクセスされたメンバ変数が存在しな いとき、代わりにどのオブジェクトを参照するかと いう参照先を指す __proto__はIEで未実装
    • 継承を実装するには__proto__を動的にたどって、__proto__の指すポインタを動的に組み替えればいい
    • 動的に__proto__をたどるこれはできない child = child.__proto__; child.__proto__ = parent; // Cyclic errorこれはできる child.__proto__.__proto__ = parent; だがこれは静的にたどってるのでNG解決策 var list = [“child”, “__proto__”, “__proto__”]; eval(list.join(“.”) + “ = parent”);
    • 親を参照するには自分自身の__proto__を参照するだけ
    • 完成形https://gist.github.com/967863
    • 問題:parentが関数になってしまうobj.parent().getName() になってしまう obj.parent.getName() が理想だったが…解決策はない 理由 parent()では自分自身(this)を参照し__proto__を参照する 自分自身(this)を参照するには関数でなければならない parentだとただのプロパティであり、thisはwindowになる 悪あがき(無名関数を駆使したり)したがやっぱり無理でした。正直、こんなことにこだわる理由はないのだが…。大した問題じゃないので次。
    • 問題:prototype汚染問題prototypeを拡張することで全コードに影響が出る問題 Object.prototype.extend Array.prototype.each など ライブラリ拡張してたりする。ライブラリ間で競合していると動かなく なる可能性がある for-inでプロパティを走査したときに拡張したメソッドが含まれるため バグを生む可能性がある回避方法 メソッド化を諦めて素直に関数を使う ラッパーオブジェクトでラップする http://d.hatena.ne.jp/cyokodog/20081031/ArrayExtend01 ライブラリを使う jQueryとかを素直に使っておけということ そのライブラリが汚染していることがあるけどね今回の場合 mix, parentを追加したので影響はある が、かぶることは(おそらく)ないので目をつぶる。for-inは気をつける。
    • 今回の方法を応用すると機能ごとの汎用オブジェクトを定義しておく var Utils = {…}; var Http = {…}; var Design = {…};各アプリごとで使いたいオブジェクトだけ継承する var obj = Base.mix(Utils).mix(Http); 名前がかぶらなければそのまま呼べる obj.xhr(); // Http#xhr 名前がかぶってもparent()で呼べる obj.parent().getObjectName(); // Utils#getObjectName汎用オブジェクトの単独使用も可能 var result = Http.xhr();他のライブラリと併用はもちろん可能
    • まとめJavaScriptのプロトタイプベースオブジェクト指向プログラミングをするための方法を説明過去のプログラムをこの方法で書きなおすかも