【フロントエンド学習】javascript対象向けプログラミング(継承と多重)


前言
      コード多重化の一モードを引き継ぐ.他の高度なプログラム言語と比べて、Javascriptは少し違っています.純粋に対象に向かっている言語です.JSには種類の概念がありませんが、原型を通して対象の継承と多状態をシミュレートすることもできます.javascriptオブジェクトの特徴によって、JSにおける継承は、参照対象の継承とインスタンスオブジェクトの継承に分類され得る.参照オブジェクトは継承され、サブ参照タイプは親参照タイプを継承し、サブ参照タイプによって生成されたインスタンスオブジェクトは、親参照タイプの特性を有する.例示的なオブジェクトの継承、継承されたオブジェクトは、親のインスタンスオブジェクトの属性と方法のすべてを持っています.つまり、オブジェクトの複製とクローンです.
  • デフォルト継承モード
  • 構築関数モードを借りる
  • 構築関数を借りてプロトタイプモードを設定する
  • 共有プロトタイプ
  • 一時プロトタイプ
  • 構築関数+一時プロトタイプパターンを借りる
  • インスタンスオブジェクトの継承には、以下のいくつかの実施形態があります.
  • 一時モデル継承
  • は、引き継ぎを可能にするために、借用およびバインディングされている(実際には多重化されている)
  • .
    参照オブジェクトの継承→デフォルトの継承モード
    デフォルトの継承パターンは簡単です.CがPを継承するなら、コードを実現します.
    function Parent(name) {
         this.name = name || 'Adam';
    }
    Parent.prototype.say = function() { return this.name;};  
    function Child(name) { };
    function inherit(C , P) {
         C.prototype = new P();
    }
    var c = new C ('xiaoxin' );   
    alert(c.say());  // 'Adam' 
    パターンの特徴:
  • CはPのすべての属性を継承しているだけでなく、Pのプロトタイプのすべての属性を継承しているが、時にはPのプロトタイプの属性だけを継承したい場合がある.
  • Cの構造関数はパラメータを伝えることができません.つまり、C構造方法にパラメータを渡すことができません.CはPの構造方法にパラメータを伝えることができます.
    参照オブジェクトの継承-構造関数を借りる
    構造関数モードを借りると、実際にはApplyまたはCallを採用して、子オブジェクトに親オブジェクトの属性を継承させるということです.具体的には、次の例を見ます.
    function Article(name) {
         this.name = name;
         this.tags =['js','css'];
     }
     var article = new Article('parent');
    
     function BlogPost() {}
     BlogPost.prototype = article;
     var blog = new BlogPost();
    
    function Parent2 (name) {        //   2
       this.name2 = name;
    }
    
     function StaticPage(name) {
         Article.apply(this,arguments);   //             
             Parent2(this,arguments);     //             
     }
     var page = new StaticPage("page");
    
      alert(article.hasOwnProperty('tags'));     //true
      alert(blog.hasOwnProperty('tags'));       // false   :           prototype    
      alert(page.hasOwnProperty('tags'));       //true   :            
    
      blog.tags.push('html');                  
      page.tags.push('php');
      alert(article.tags.join(','));           // js,css,html   :                ;           ,              
    パターンの特徴:
  • は、このように継承することにより、各サブオブジェクトが親オブジェクトの属性を有し、この属性は親オブジェクト属性のコピー(非参照)であるため、子オブジェクトが相続の属性を修正することによって親オブジェクト属性がカバーされるリスクはない.
  • このように実現された相続は、1つのサブオブジェクトが複数の親オブジェクトを継承することができ、
  • サブオブジェクトは、親オブジェクトの属性しか継承できませんが、親オブジェクトのプロトタイプオブジェクトの属性は継承できません.
  • 参照オブジェクトの継承-構造関数の借用とプロトタイプの設定
    このモードは、実際には、デフォルトの継承モードと構造関数の組み合わせによって実現されるモードであり、このモードは、前の2つのモードに存在するいくつかの問題を解決することができ、具体的には次の例を参照してください.
       function StaticPage(name) {
         Article.apply(this,arguments);   //             
    // Parent2(this,arguments); //                
       }
      StaticPage.prototype = new Article();   //    
    パターンの特徴:
  • このようなモードは、親オブジェクトの属性が2回引き継がれることになり、効率が低下します.
    引用対象継承-共有プロトタイプ
    共有プロトタイプの原理は、サブオブジェクトと親オブジェクトが一つのプロトタイプを共有することです.すなわち、親オブジェクトのプロトタイプは、以下の例を参照してください.
    StaticPage.prototype = Article.prototype;  //    
    パターンの特徴:
  • このようなモードはほぼ完璧です.上のパターンの問題はほとんどありません.ただ一つの注意が必要です.サブオブジェクトと親オブジェクトが一つのプロトタイプを共有しているため、あるサブオブジェクトがプロトタイプの属性を変更すると、親オブジェクトのプロトタイプも変化し、すべてのサブオブジェクトインスタンスが変化します.
  • 参照対象継承-一時プロトタイプモード
    前に述べましたが、デフォルトの継承モードは、親類のオブジェクトの一部を継承したくない属性を共有することができますが、共有モデルは親類のオブジェクト属性が修正されるリスクがあります.どうすればいいですか?一時的なコンストラクションモードでは、上記の問題をうまく解決しました.一時的な関数モードの原理は、親類のオブジェクトだけを継承します.親類のプロトタイプのプロトタイプを使用しません.サブクラスのオブジェクトに直接与えられるプロトタイプ属性ではなく、サードパーティ関数のオブジェクトを参照して、このサードパーティ関数のオブジェクトのプロトタイプをこのサードパーティ関数のオブジェクトのプロトタイプに値を付けて、このサードパーティ関数オブジェクトのインスタンスオブジェクトをサブオブジェクトのプロトタイプとします.
    function inherit(C,P) {  //   Object.create()        (ES5)
    var F = function() {};   //           
    F.prototype = P.prototype  //      (         protype   )
    C.prototype = new F(); //  ,                     
    C.uber = P.prototype ; //          ,            (  )
    C.prototype.constructor = C;   //   constructor  
    参照先継承-コンストラクタ+一時プロトタイプモード
    この方法は、プロトタイプが存在する親オブジェクトの属性を2回引き継ぐことで効率が低下する問題を解決するために、どのように実現されますか?
    function Child() {//  Parent       
        Parent.call(this);  
    }  
    //inherit         
    inherit(Child, Parent);
    この方法は最も適切であり、最も広く継承されたモデルでもあります.nodejsでは、このような方式で継承を実現することを推奨します.例えば、EventEmitter引用のタイプを継承したいです.コードは以下の通りです.
    function MyEvent() { 
        events.EventEmitter.call(this);  
    }  
    util.inherits(MyEvent, events.EventEmitter);//      EventEmitter 
    インスタンスオブジェクト継承-原型継承
    現代の継承と伝統の継承は違って、クラスの継承ではなく、オブジェクトの継承を指します.その本質は、オブジェクトを作成し、親オブジェクトと同じ属性を持っています.
    function object(parent) {   //         
       var F =  function() {};   //          
       F.prototype = parent;
       return  new F();    //          
    }
    function Person() {
       this.name = 'xiaoxin';
    }
    Person.prototype.getName = function() { return this.name; }
    var pa = new Person();
    var kid = object(pa);
    alert(pa.name);  // xiaoxin         
    alert(kid.getName());   //xiaoxin        prototype  
    インスタンスオブジェクトの継承→オブジェクトの複製(クローン)
    オブジェクトの複製も対象継承の一つです.以下は簡単な浅いクローン方式です.正確なオブジェクトの複製が必要なら、深いクローンを採用することをお勧めします.Jqueryでは、大量の深度クローンを適用して、jquery機能とプラグインの拡張を実現します.
    function extend(parent,child) {  //        
        var att ;
        child = child || {};
        for(i in parent) {
           if(parent.hasOwnProperty(i)) {
             child[i] = parent[i];
           }
         }
      return child;
    }
    インスタンスオブジェクトの継承-参照とバインディング
    前述のようにオブジェクト複製というパターンは、親オブジェクトのすべての属性を複製し、サブオブジェクトを生成し、親オブジェクトにおける属性コードの多重化を実現しています.しかし、親オブジェクトのすべての属性を多重する必要はなく、ある属性だけを使用する必要があります.この場合は、借用モードを採用して実現することが考えられます.原理:applyまたはcallを用いてオブジェクト内の方法の多重化を実現する.具体的には次の例を参照してください.
    //              slice()  ,       arguments    
    function f() {
     var args = [].slice.call(arguments,1,3);//    Array  slice  。
    // var args = Array.prototype.slice.call(arguments,1,3); //         ,              
       return args;
     }
    f(1,2,3,4,5,6);         //   [2,3] 
    面の上のモードは普通の方法で使用されていますが、多重化された方法にはthisキーワードが含まれています.また、この方法はグローバル方法またはコールバック関数として伝達されています.
    var one = {
      name : "object",
      say: function(greet) {   return  greet+","+this.name; }       //           this   
     }
    one.say('hi');   // hi,object
    var two = { name: 'another object' };
    one.say.apply(two, ['hello']) ;    // hello,another object //      ,           two 
    
    var say = one.say;
     say('hello');   //hello,underfined      ,   this     ,     name 
    
    var yetanother = {
       name: 'yet another object',
      method: function(callback) {
                     return callback('Hola');
                   }
    }
    yetanother.method(one.say);   // Hola,underfined      ,   this     ,     name 
    面以上の例は、多重化する場合は、多重化されたオブジェクトと多重化された方法をバインディングしなければならないが、グローバルオブジェクトまたはコールバック関数の形はバインディングされていないということを示しています.
       function bind(method,obj) {
        //       return       function  
         return function() { 
         //    
          return method.apply(obj,[].slice.call(arguments));      
         };
      }
     //    var say = function() { return one.say.apply(two,[].slice.call(arguments));}
     var say = bind(one.say,two);   
    say('hello');       //hello,another object