JavaScriptでの継承方法の詳細

8535 ワード

js継承の概念
jsでよく使われる継承方法は次の2つです.
プロトタイプチェーン継承(オブジェクト間の継承)クラス式継承(コンストラクション関数間の継承)jsはjavaのように本当にオブジェクト向けの言語ではないため、jsはオブジェクトベースであり、クラスの概念はない.したがって、継承を実現するには、jsのプロトタイプprototypeメカニズムまたは者でapplyとcallメソッドで実現することができる
オブジェクト向け言語では、クラスを使用してカスタムオブジェクトを作成します.しかしjsのすべてのものはオブジェクトですが、カスタムオブジェクトを作成するにはどのような方法がありますか?これはjsのプロトタイプを使用する必要があります.
簡単にprototypeをテンプレートと見なすことができ、新しく作成されたカスタムオブジェクトはすべてこのテンプレート(prototype)のコピーである(実際にはコピーではなくリンクであるが、このリンクは見えないが、新しいインスタンス化されたオブジェクトの内部には見えない__Proto_ポインタがあり、プロトタイプオブジェクトを指す).
jsは関数とプロトタイプを構築することによってクラスの機能をシミュレーションすることができる.またjsクラス継承の実現もプロトタイプチェーンによって実現される.
プロトタイプ継承とクラス継承
クラス継承は、サブタイプコンストラクション関数の内部でスーパータイプを呼び出すコンストラクション関数です.厳密なクラス継承はあまり一般的ではありませんが、一般的には組み合わせて使用されます.
 
  
function Super(){
    this.colors=["red","blue"];
}

function Sub(){
    Super.call(this);
}


プロトタイプ継承は、既存のオブジェクトを使用して新しいオブジェクトを作成し、サブクラスのプロトタイプを親に向けることで、親というプロトタイプチェーンを追加することに相当します.
プロトタイプチェーン継承
親の属性(メソッドも含む)を子に継承するには、まずコンストラクション関数を定義する必要があります.次に、親の新しいインスタンスをコンストラクション関数のプロトタイプに割り当てます.コードは次のとおりです.
 
  
<br>     function Parent(){ <br>         this.name = 'mike'; <br>     } <p></p> <p>    function Child(){<br>         this.age = 12;<br>     }<br>     Child.prototype = new Parent();//Child Parent, , </p> <p>    var test = new Child();<br>     alert(test.age);<br>     alert(test.name);// <br>     // <br>     function Brother(){   //brother <br>         this.weight = 60;<br>     }<br>     Brother.prototype = new Child();// <br>     var brother = new Brother();<br>     alert(brother.name);// Parent Child, mike<br>     alert(brother.age);// 12<br>

以上のプロトタイプチェーン継承には、すべてのコンストラクション関数がObjectから継承されるObjectというループが欠けています.継承Objectは自動的に完成し、私たち自身が手動で継承する必要はありません.では、彼らの従属関係はどうなっていますか.
プロトタイプとインスタンスの関係の決定
プロトタイプとインスタンスの関係は、2つの方法で決定できます.オペレータinstanceofおよびisPrototypeof()メソッド:
 
  
alert(brother instanceof Object)//true
alert(test instanceof Brother);//false,test brother
alert(brother instanceof Child);//true
alert(brother instanceof Parent);//true

プロトタイプチェーンに出現したプロトタイプであれば,いずれもそのプロトタイプチェーンが派生したインスタンスのプロトタイプといえるため,isPrototypeof()メソッドもtrueを返す.
jsでは、継承された関数をスーパータイプ(親、ベースクラスでも行)、継承された関数をサブタイプ(子、派生クラス)と呼びます.プロトタイプ継承を使用するには、主に2つの問題があります.1つは、プロトタイプを字面量で書き換えると関係が中断され、参照タイプのプロトタイプが使用され、サブタイプがスーパータイプにパラメータを渡すことができないことです.
擬似クラスは、リファレンス共有とスーパータイプではパラメータが伝達されないという問題を解決し、構造関数の借用技術を採用することができます.
コンストラクタの借用(クラス継承)
 
  
<br>     function Parent(age){ <br>         this.name = ['mike','jack','smith']; <br>         this.age = age; <br>     } <p></p> <p>    function Child(age){<br>         Parent.call(this,age);<br>     }<br>     var test = new Child(21);<br>     alert(test.age);//21<br>     alert(test.name);//mike,jack,smith<br>     test.name.push('bill');<br>     alert(test.name);//mike,jack,smith,bill<br>

借用構造関数は先ほどの2つの問題を解決したが,プロトタイプがなければ多重化は語れないため,プロトタイプチェーン+借用構造関数のモードが必要であり,このモードを組合せ継承と呼ぶ.
グループ継承
 
  
<br>     function Parent(age){ <br>         this.name = ['mike','jack','smith']; <br>         this.age = age; <br>     } <br>     Parent.prototype.run = function () { <br>         return this.name  + ' are both' + this.age; <br>     }; <br>     function Child(age){ <br>         Parent.call(this,age);// , <br>     } <br>     Child.prototype = new Parent();// <br>     var test = new Child(21);// new Parent(21) <br>     alert(test.run());//mike,jack,smith are both21 <br>

コンビネーション継承は、プロトタイプチェーンを使用してプロトタイプ属性とメソッドの継承を実現し、コンストラクション関数を借りることでインスタンス属性の継承を実現するという考え方の背後にある比較的一般的な継承方法です.これにより,プロトタイプ上でメソッドを定義することによって関数多重化が実現され,各インスタンスに独自の属性があることが保証される.
call()の使い方:現在のオブジェクトを別のオブジェクトに置き換えるメソッドを呼び出します.
 
  
call([thisObj[,arg1[, arg2[, [,.argN]]]]])

プロトタイプ継承
この継承は、プロトタイプを使用して既存のオブジェクトに基づいて新しいオブジェクトを作成し、カスタムタイプを作成することなくプロトタイプ継承と呼ばれます.
 
  
<br>      function obj(o){ <br>          function F(){} <br>          F.prototype = o; <br>          return new F(); <br>      } <br>     var box = { <br>         name : 'trigkit4', <br>         arr : ['brother','sister','baba'] <br>     }; <br>     var b1 = obj(box); <br>     alert(b1.name);//trigkit4 <p></p> <p>    b1.name = 'mike';<br>     alert(b1.name);//mike</p> <p>    alert(b1.arr);//brother,sister,baba<br>     b1.arr.push('parents');<br>     alert(b1.arr);//brother,sister,baba,parents</p> <p>    var b2 = obj(box);<br>     alert(b2.name);//trigkit4<br>     alert(b2.arr);//brother,sister,baba,parents<br>

プロトタイプ継承は、まずobj()関数の内部に一時的なコンストラクション関数を作成し、次に入力されたオブジェクトをこのコンストラクション関数のプロトタイプとし、最後にこの一時的なタイプの新しいインスタンスを返します.
スプリアス継承
この継承方式はプロトタイプ+ファクトリモードを結合し,作成プロセスをカプセル化することを目的とする.
 
  
<br>     function create(o){ <br>         var f= obj(o); <br>         f.run = function () { <br>             return this.arr;// , <br>         }; <br>         return f; <br>     } <br>

コンビネーション継承の小さな問題
コンビネーション継承はjsで最も一般的な継承モードであるが、コンビネーション継承のスーパータイプは使用中に2回呼び出される.1つはサブタイプを作成するとき、もう1つはサブタイプコンストラクション関数の内部
 
  
<br>     function Parent(name){ <br>         this.name = name; <br>         this.arr = [' ',' ',' ']; <br>     } <p></p> <p>    Parent.prototype.run = function () {<br>         return this.name;<br>     };</p> <p>    function Child(name,age){<br>         Parent.call(this,age);// <br>         this.age = age;<br>     }</p> <p>    Child.prototype = new Parent();// <br>

以上のコードが以前の組合せ継承であると,寄生組合せ継承は,2回の呼び出しの問題を解決する.
スプリアスコンビネーション継承
 
  
<br>     function obj(o){ <br>         function F(){} <br>         F.prototype = o; <br>         return new F(); <br>     } <br>     function create(parent,test){ <br>         var f = obj(parent.prototype);// <br>         f.constructor = test;// <br>     } <p></p> <p>    function Parent(name){<br>         this.name = name;<br>         this.arr = ['brother','sister','parents'];<br>     }</p> <p>    Parent.prototype.run = function () {<br>         return this.name;<br>     };</p> <p>    function Child(name,age){<br>         Parent.call(this,name);<br>         this.age =age;<br>     }</p> <p>    inheritPrototype(Parent,Child);// </p> <p>    var test = new Child('trigkit4',21);<br>     test.arr.push('nephew');<br>     alert(test.arr);//<br>     alert(test.run());// </p> <p>    var test2 = new Child('jack',22);<br>     alert(test2.arr);// <br>

callとapply
グローバル関数applyとcallは、次のように関数内のthisの指向を変更するために使用できます.
 
  
//
    function foo() {
        console.log(this.fruit);
    }

    //
    var fruit = "apple";
    //
    var pack = {
        fruit: "orange"
    };

    // window.foo();
    foo.apply(window);  // "apple", this window
    // foo this === pack
    foo.apply(pack);    // "orange"