javascriptの構造関数、プロトタイプとその実現の経典で継承します.

7487 ワード

javascriptを使ってオブジェクトを実現するには、一般的に最もよく使われる方法はプロトタイプを作ることです.
function Person(name,age,college){
        this.name = name;
        this.age = age;
        this.college = college;
        this.sayName = function () {
            alert(this.name);
        }
    }
    var person1 = new Person("xuZhiWei",22,"Nanjing University of Science and Technology");

    var person2 = new Person("zhaochao",23,"Nanjing University");
    person1.sayName();//     xuZhiWei;
    person2.sayName();//zhaochao;
    alert(person1.age);//22;
    alert(person2.age);//23;
ここでコンストラクタの方法で2つのオブジェクトのperson 1とperson 2を作成しました.コンストラクタを使ってそれぞれ独立した属性を作成することができますが、一つの小さな欠点があります.各newのPersonは、関数を一度実例化します.たとえば、person 1.sayName=person 2.sayNameを判断します.結果はfalseです.したがって、これは確実に新しい例を証明しています.これはメモリのオーバーヘッドを増加させる.
もう一つの方法はプロトタイプのプロトタイプを利用してコンストラクションを作成し、プロトタイプオブジェクトを作成し、コンストラクターのプロトタイプ属性がプロトタイプオブジェクトを指すと同時に、プロトタイプオブジェクトのconstruction属性もPersonを指します.例は以下の通りです
function Person(){}
    Person.prototype.name="xuZhiWei";
    Person.prototype.age=22;
    Person.prototype.sayName=function(){
        return this.name;
    };
    alert(typeof Person.prototype.constructor =="function");//true
私たちはまずコンストラクションを宣言して、そのプロトタイプに値を付けて、コンストラクションを判断する時、そのタイプはfunctionです.これはコンストラクタを指しています.コンストラクタはprototype属性があるので、インスタンスにもprototype属性があるはずですが、直接アクセスできません.jsはisProttype方法を提供して判断します.以下の例は、すべての例がこのプロトタイプを指していることを証明することができる.
function Person(){}
    Person.prototype.name="xuZhiWei";
    Person.prototype.age=22;
    Person.prototype.sayName=function(){
        return this.name;
    };
    var person1 = new Person();
    var person2 = new Person();
    alert(Person.prototype.isPrototypeOf(person1));//true;
    alert(Person.prototype.isPrototypeOf(person2));//true;
    alert(typeof Person.prototype.constructor =="function");//true
これはすべての例が構造関数のプロトタイプを指していることを示しており、それらの参照は関数を含めて同じであるべきであり、この場合はperson 1.sayName==person 2.sayname戻り値はtrueであり、参照は同じであると説明している.いくつかの属性を書き換えたい場合は、インスタンスにのみ値が与えられます.
function Person(){}
    Person.prototype.name="xuZhiWei";
    Person.prototype.age=22;
    Person.prototype.sayName=function(){
        return this.name;
    };
    var person1 = new Person();
    var person2 = new Person();
    person1.name = "zhaochao";
    alert(person1.name);//zhaochao
    alert(person2.name);//xuZhiWei;
最初の表示はzhaochaoであり、2番目の表示はxuZhiWeiであり、これはインスタンスの割当値を示しています.これはプロトタイプの値を変更するのではなく、プロトタイプの値を遮蔽することができます.
プロトタイプ関数などを使用して共有できますが、参照タイプの属性には問題があります.参照タイプの属性が変更されると、すべての配列が変更されます.
 function Person(){}
    Person.prototype.name="xuZhiWei";
    Person.prototype.age=22;
    Person.prototype.hobbies=["   ","   ","   "];
    Person.prototype.sayName=function(){
        return this.name;
    };
    var person1 = new Person();
    var person2 = new Person();
    person1.hobbies.push("  ");
    alert(person1.hobbies);//   ,   ,   ,  ;
    alert(person2.hobbies);//   ,   ,   ,  ;
これらの2つのオブジェクトの結果は同じ値を返していることが分かりました.これは、参照の種類(類似または日付、正則)について、毎回の割当値が原型から修正された結果を示しています.原型には限界があります.
コンストラクタに連絡して、配列をコンストラクタで宣言すれば、自然にこの問題は発生しません.この二つの方法を組み合わせて、次のようにすることができます.
function Person(name,age){
        this.name = name;
        this.age = age;
        this.hobbies=["   ","   ","   "];
    }
    Person.prototype.sayName=function(){
        return this.name;
    };
    var person1 = new Person();
    var person2 = new Person();
    person1.hobbies.push("  ");
    alert(person1.hobbies);//   ,   ,   ,  ;
    alert(person2.hobbies);//   ,   ,   ;
ここでは、構造関数を使って参照を作成するたびに、新しい配列が発生します.これまでの問題は発生しません.また、prototypeを字面量で定義するなら、そのconstructは構造函数ではなくObjectを指します.この構造方法は使わないほうがいいです.
プロトタイプでプロトタイプチェーンの継承が実現された場合、このようにすることができます.
function Personchild(name){
    this.name = name;
}
Personchild.prototype = new Person();
このようにPersonchildのプロトタイプオブジェクトもPersonのプロトタイプを指しています.これらはすべてPersonchildのプロトタイプ属性です.そして、親の属性方法を呼び出すことができます.以下の通りです
function Person(name,age){
        this.name = name;
        this.age = age;
        this.hobbies=["   ","   ","   "];
    }
    Person.prototype.sayName=function(){
        return this.name;
    };
    function Personchild(name){
        this.name = name;
    }
    Personchild.prototype = new Person();//  Personchild prototype    Person prototype.
    var child = new Personchild("   ");
    alert(child.hobbies);//   ,   ,   ;
サブクラスも親タイプの属性を呼び出すことに成功したと見られます.しかし、これはもう一つの問題があります.最初にPersonオブジェクトを宣言してからHobriesの値を修正すると、配列は参照のタイプですから、この結果はサブクラスにも影響を与えます.
function Person(){
        this.hobbies=["   ","   ","   "];
    }
    function Personchild(){}
    Personchild.prototype = new Person();//  Personchild prototype    Person prototype.
    var child1 = new Personchild();
    child1.hobbies.push("  ");
    var child2 = new Personchild();
    alert(child2.hobbies);//   ,   ,   ,  ;
各例の指し示すプロトタイプは、継承されたホビー属性があるので、これは構造関数のホビーとは違って、実用化された新しい配列ですが、サブクラスのプロトタイプでは、この配列を共有しています.値が変わると、値が変化します.
この問題を解決するために、構造関数を借りる技術を使うことができます.この方法は簡単です.実例コードは以下の通りです.
function Person(){
        this.hobbies=["   ","   ","   "];
    }
    function Personchild(){
        Person.call(this);//         ;
    }
    var child1 = new Personchild();
    child1.hobbies.push("  ");
    alert(child1.hobbies);//   ,   ,   ,  ;
    var child2 = new Personchild();
    alert(child2.hobbies);//   ,   ,   ;
私たちは、call()方法またはapply()方法を呼び出すことによって、Javaのsuper()と同様の効果を達成することができ、このように、各サブクラスのインスタンスは、自分のhobriesコピーを持つことができる.
パラメータを渡すなら、thisの後ろにパラメータを足せばいいです.たとえば、call(this、「zhaochao」).
しかし,コンストラクタを作成する方法については,前に述べた問題が残っているので,一般的には借用構造関数とプロトタイプチェーンを組み合わせて使用し,組み合わせ継承を構成している.
最後の組み合わせのコードは以下の通りです.
function Person(name){
        this.name = name;
        this.hobbies=["   ","   ","   "];
    }
    Person.prototype.sayName = function () {
        alert(this.name);
    };
    Person.prototype.sayHobbies = function () {
        alert(this.hobbies);
    };
    function Personchild(name,age){
        Person.call(this,name);//         ;
        this.age = age;
    }
    Personchild.prototype = new Person();
    Personchild.prototype.sayAge = function () {
        alert(this.age);
    };
    var instance1 = new Personchild("   ",22);
    instance1.hobbies.push("  ");
    instance1.sayName();//   ;
    instance1.sayAge();//22;
    instance1.sayHobbies();//"   ","   ","   ","  ";
    var instance2 = new Personchild("  ",55);
    instance2.sayName();//  
    instance2.sayAge();//55
    instance2.sayHobbies();//"   ","   ","   ";
はこの例では、構造関数の属性は各例に属し、プロトタイプのプロトタイプの方法は共通であり、このように構造関数とプロトタイプチェーンの利点を組み合わせている.書いたのはちょっと多いですが、後で見たら一瞬で分かりますように.