JavaScriptは作成対象から継承まで

15432 ワード

オブジェクトを作成
jsの継承をプレイする前に、jsの対象を作成します.JavaScriptアドバンストプログラムの設計には、単一のオブジェクトをカスタマイズする二つの方法が紹介されています.
  • Objectを作成します.例
  • var person = new Object()
    //     
    person.name = "Nick"
    person.age = 29
    person.job = "FrontEnd Engineer"
    //     
    person.sayName = function() {
        console.log(this.name)
    }
    
  • オブジェクトの字面量の方式
  • var person = {
        //     
        name: "Nick",
        age: 29,
        job: "FrontEnd Engineer",
        //     
        sayName: function() {
         console.log(this.name)
        }
    }
    
    以上の2つの方法は、単一のpersonオブジェクトを作成しました.この2つのpersonオブジェクトは同じです.操作子を通してオブジェクトの属性にアクセスできます.例えば、person.nameの値は「Nick」です.
    もし私たちが今他のpersonオブジェクトを作成するなら、person 2と仮定して、私たちは相変わらず上の2つの方法でperson 2を作成することができます.そこで、私たちはまたperson 2のためにname、age…これらの属性を設定します.問題が来ました.世界中に辛い人がいますか?私達はずっとこのように作っていくことができないでしょう.
    この時、私たちはname、age、jobなどの識別的な属性を入力すると、必要なオブジェクトを返してくれる関数がほしいです.したがって、私たちは同じオブジェクトのコードを作成するために手動で多くの重複コードを書かなくてもいいです.
    これは工場モードで一括作成の対象です.
        //     
        function createPerson(name, age, job) {
          var obj = new Object()
          obj.name = name
          obj.age = age
          obj.job = job
          obj.sayName = function() {
            console.log(this.name)
          }
          return obj
        }
    
        var person1 = createPerson("  ", 33, "   ")
        person1.sayName() // "  "
    
        var person2 = createPerson("  ", 23, "   ")
        person2.sayName() // "  "
    
    工場モードは重複コードを書かない問題を解決しましたが、オブジェクト識別問題が解決されていません.つまり、person 1とperson 2はどのタイプに属しているか分かりません.
    さもなくばあなたは辛い何の多いpersonを創建して、しかしそれらを分類することができなくて、あなたがまた多くのdogの対象を創建した時、personとdogは混じっていっしょにいて、それからあなたは人が人ではないことを見て、犬を見るのは犬ではありませんでした.
    JavaScriptの発展に伴って、もう一つの新しいモードが現れました.すなわち、構造関数モードです.
        //     ,            ,           
        function Person(name, age, job) {
          //     ,    this  ,this  Person    
          this.name = name
          this.age = age
          this.job = job
          //     
          this.sayName = function() {
            console.log(this.name)
          }
        }
        
        var person1 = new Person("  ", 33, "   ")
        person1.sayName() // "  "
        var person2 = new Person("  ", 23, "   ")
        person2.sayName() // "  "
    
    構造関数モードは、newオペレータを使用してオブジェクトのインスタンスを作成します.オブジェクトのインスタンスですか?それともオブジェクトですか?その作成プロセスには4つのステップがあります.
  • 空きオブジェクトを作成します.var person 1={}
  • Personコンストラクタの役割領域をperson 1に与えます.コンストラクタのthisはperson 1
  • を指します.
  • は、構造関数内のコードを実行します.person 1オブジェクトに属性または方法を追加します.
  • は、新たなオブジェクトperson 1に戻る(2、3のステップで加工された)
  • .
    コンストラクターモードを通じて、私たちが作成したperson 1,person 2は明確な分類があります.すなわち「Personクラス」です.工場モードの対象識別問題を解決しました.
    しかし、コンストラクションモードを通じて、私たちはpersonのインスタンスを作成するたびに、ステップ3を実行します.すなわち、オブジェクトに与えられた属性を実行します.name、ageなどの区別が必要な属性は確かに実行する必要がありますが、各personはsayName方法があります.関数を作成するにはメモリを消費する必要があります.ここでは2回作成します.そこで私たちはあらかじめ関数を作成して、インスタンスを作成する時に引用すればいいです.
        //     ,            ,           
        function Person(name, age, job) {
          //     ,    this  ,this  Person    
          this.name = name
          this.age = age
          this.job = job
          //     
          this.sayName = sayName
        }
    
        function sayName() {
          console.log(this.name)
        }
    
    以上のコードはグローバルスコープでsayName関数を作成しました.以降は毎回引用すればいいです.毎回作成しなくてもいいです.目的はすでに達成されたようです.ココアですが、これはパッケージ性がなく、グローバル変数の汚染をもたらします.
    この問題を解決する方法は何がありますか?構造関数の原型オブジェクトで定義されています.
        //     ,            ,           
        function Person(name, age, job) {
          //     
          this.name = name
          this.age = age
          this.job = job      
        }
    
        //           
        Person.prototype.sayName = function() {
          console.log(this.name)
        }
    
        var person1 = new Person("  ", 33, "   ")
        person1.sayName() // "  "
        var person2 = new Person("  ", 23, "   ")
        person2.sayName() // "  "
    
    ここでは、原型の対象を簡単に紹介します.いつでも、関数を作成すると、この関数は属性プロトタイプを持っています.このプロトタイプは関数のプロトタイプのオブジェクトを指します.
        function Person(name, age, job) {
          //     
          this.prototype =          
          //     
          this.name = name
          this.age = age
          this.job = job      
        }
    
    カスタムコンストラクタのプロトタイプオブジェクト(たとえば、本明細書のPersonコンストラクタ)は、デフォルトでは一つのコンストラクタ属性しかないです.このconstructorの属性はPerson()を指します.他にもObjectから引き継がれる方法がありますが、ここではそんなに多くないです.
    関数のプロトタイプオブジェクトで定義されている属性については、ここで2点だけを説明します.
  • 関数プロトタイプオブジェクト上の属性と方法はすべてのインスタンスで共有され、値タイプは上書きできますが、書き換えはできません.
    function Person(name, age) {
          //     
          this.name = name
          this.age = age   
        }
    
        Person.prototype.job = "  "
    
        var person1 = new Person("  ", 33)
        console.log(person1.job) // "  "
        //   
        person1.job = "  "
        console.log(person1.job) // "  "
    
        var person2 = new Person("  ", 43)
        //     
        console.log(person2.job) // "  "
    
  • は、プロトタイプオブジェクトに定義される参照タイプの値については、修正可能である:
  • function Person(name, age) {
          //     
          this.name = name
          this.age = age   
        }
    
        Person.prototype.job = ["  ", "  ", "web  "]
    
        var person1 = new Person("  ", 33)
        console.log(person1.job) // ["  ", "  ", "web  "]
        //   
        person1.job.shift()
        console.log(person1.job) // ["  ", "  "]
    
        var person2 = new Person("  ", 43)
        //     
        console.log(person2.job) // ["  ", "  "]
    
    Person関数のプロトタイプオブジェクトにsayName方法を定義した後、インスタンスのperson 1とperson 2はいずれもsayName()にアクセスでき、また訪問したのは同じsayName()であり、これはsayName()が2回作成される問題を解決した.
    JavaScript高級プログラムの設計にはいくつかの作成対象方式と原型の対象についての詳しい説明がありますが、ここでは触れません.必要なものがあれば行ってみてください.次に私たちは正式にJavaScriptの継承について話します.
    引き継ぐ
    JavaScriptの継承は継承を実現すること、すなわち実際を継承する方法である.プロトタイプチェーンに基づいています.
    JavaScriptはなぜ継承が必要ですか?
    上記の構造関数Personを振り返ってみます.
        //     ,            ,           
        function Person(name, age, job) {
          //     
          this.name = name
          this.age = age
          this.job = job      
        }
    
        //           
        Person.prototype.sayName = function() {
          console.log(this.name)
        }
    
        var person1 = new Person("  ", 33, "   ")
        person1.sayName() // "  "
        person1.age // 33
        person1.job // "   "
    
    現在、似たようなmanオブジェクトを複数作成する必要があると仮定すると、Man()構造関数によって作成する必要があります.このMan()構造関数はPerson構造関数のすべての属性と方法を持っています.また、自分の属性と方法を持っています.
    この時、私達は重複コードを書かないために(PersonコンストラクションによってManを実現します)、多くのOO言語の経験によって、Person定義の属性と方法を継承できればいいなと思いました.
    相手の継承はどうやって実現しますか?
    JavaScript特色のプロトタイプチェーンを使う方式
    1.組合せ相続(偽経典相続)
    ペrsonの内部およびプロトタイプに定義されているすべての属性と方法を例としたperson 1は、Man()構造関数のプロトタイプオブジェクトがperson 1に等しい場合、何が発生しますか?
    はい、そうですMan()のプロトタイプのオブジェクトにはPersonプロトタイプのオブジェクト上のすべての属性と方法があります.コードを見てください.
        //     ,            ,           
        function Person(name, age, job) {
          //     
          this.name = name
          this.age = age
          this.job = job      
        }
    
        //           
        Person.prototype.sayName = function() {
          console.log(this.name)
        }
    
        var person1 = new Person()
    
        // Man    
        function Man() {
          //          
          this.name = "ironman"
        }
        
        //           ,         prototype              
        //    Man prototype         ,      person1
        Man.prototype = person1
    
        var man1 = new Man()
        //         Man      sayName   
        //     sayName()   this  man1,  this               ,    sayName      man1
        man1.sayName() // ironman
        console.log(person1.age) // undefined
        console.log(person1.job) // undefined
    
    以上のコードの中でMan()はPerson()のプロトタイプのsayNameメソッドを継承していますが、Person()内部のプライベート属性(name,age,job)は引き継がれていません.これらの属性は共有できないので、原型の対象として定義できないです.どうやって継承できますか?
    私たちはコンストラクタも関数であり,また呼び出されることができることを知っています.ただコンストラクタはオブジェクトを作成するためにも使えるだけです.だから、私たちはMan()の内部でPerson()を呼び出してみよう.
    //     ,            ,           
        function Person(name, age, job) {
          //     
          this.name = name
          this.age = age
          this.job = job      
        }
    
        //           
        Person.prototype.sayName = function() {
          console.log(this.name)
        }
    
        var person1 = new Person()
    
        // Man    
        function Man(name, age, job) {
          //   Person(), Person() this    Man(),       
          Person.call(this, name, age, job)
          //          
          this.hobby= "play ironman"
        }
        
        //           ,         prototype              
        //    Man prototype         ,      person1
        Man.prototype = person1
    
        var man1 = new Man("    ", 23, "   ")
       
        man1.sayName() // "    "
        console.log(person1.age) // 23
        console.log(person1.job) //    
    
    以上のコードは、Man()にパラメータを受け取り、Person()にパラメータを伝えました.Man()の内部にはname、age、jobフィールドがあります.だからPerson()の内部の属性を継承しました.このようなサブタイプのコンストラクタの内部で親タイプのコンストラクタを呼び出す方法を借用コンストラクタといいます.
    私有属性を継承し、原型の対象に定義する方法が完成しました.ここでもう一つの問題があります.Person()の原型の対象のconstrutor属性を覚えていますか?Person()を指しています.だから、Man()の原型の対象のconstructorはMan()を指すべきです!
    理論は実践に及ばず、Manの内部にthis.co nstructorを印刷してみたら、Person()が印刷されていることが分かります.
    どういうことですか?理屈は簡単で、Man()の原型の対象は変わって、今は実例の対象のperson 1なので、Man()の原型の対象のconstructor属性はperson 1の原型の対象のconstrutorによって指すべきです.
    person 1はPerson()によって作成されたので、person 1の原型オブジェクト上のconstructorはPerson()を指します.これはよく検証しました.前にPerson()が印刷されました.
    間違いを指摘した以上、帰ってきてください.
        ...    
        //           ,         prototype              
        //    Man prototype         ,      person1
        Man.prototype = person1
        //  Man       constructor  Man()
        Man.prototype.constructor = Man
        ...
    
    以上の完全コードは以下の通りです.
        //     ,            ,           
        function Person(name, age, job) {
          //     
          this.name = name
          this.age = age
          this.job = job      
        }
    
        //           
        Person.prototype.sayName = function() {
          console.log(this.name)
        }
    
        var person1 = new Person()
    
        // Man    
        function Man(name, age, job) {
          //   Person(), Person() this    Man(),       
          Person.call(this, name, age, job)
          //          
          this.hobby= "play ironman"
        }
        
        //           ,         prototype              
        //    Man prototype         ,      person1
        Man.prototype = person1
        //  Man       constructor  Man()
        Man.prototype.constructor = Man
    
        //  Man         
        Man.prototype.sayHobby = function() {
          console.log(this.hobby)
        }
    
        var man1 = new Man("    ", 23, "   ")
       
        man1.sayName() // "    "
        man1.sayHobby() // "play ironman"
        console.log(person1.age) // 23
        console.log(person1.job) //    
    
    上記の例により、グループ継承の一般的な形式が得られます.
        //    
        function Super (name) {
          this.name = name
          this.color = ['blue', 'red', 'yello']
        }
        Super.prototype.sayName = function () {
          console.log(this.name)
        }
    
    
        //    
        function Sub (name, age) {
          //           ,    
          Super.call(this, name)
          this.age = age
        }
    
        //               ,      constructor           
        //     
        Sub.prototype = new Super()
        //        constructor    
        Sub.prototype.constructor = Sub
    
        //          
        Sub.prototype.sayAge = function () {
          console.log(this.age)
        }
    
        //        1,           
        var instance1 = new Sub('lol', 22)
        instance1.color.push('pink')
        console.log(instance1.color) // ['blue', 'red', 'yello','pink']
        instance1.sayName() // 'lol'
        instance1.sayAge() // 22
    
        //        2,               1      
        var instance2 = new Sub('oop', 33)
        console.log(instance2.color) // ['blue', 'red', 'yello']
        instance2.sayName() // 'oop'
        instance2.sayAge() // 33
    
    2.原型式継承(値タイプ継承)
    本質的には、プロトタイプ継承はカスタムコンストラクタを考慮しないで、親オブジェクトに対しては一回だけ浅いコピーです.
        //       ,             ,          
        function object (o) {
          //         F
          function F() {}
          //   F         
          F.prototype = o
          //                F   
          return new F()
        }
        
        //        
        var person = {
          name: 'seven',
          friends: ['blob', 'micelid', 'jerry']
        }
        
        //    1
        var man1 = object(person)
        man1.friends.shift() //         
        console.log(man1.name) // 'seven'
        console.log(man1.friends) // ['blob', 'micelid', 'jerry']
        
        //    2
        var man2 = object(person)    
        console.log(man1.name) // 'seven'
        console.log(man1.friends) // ['blob', 'micelid']      1   friends
    
    プロトタイプの継承に注意したいのは、親オブジェクトの参照の種類が異なるインスタンスによって修正されます.
    es 5はObject.creat()関数によりプロトタイプ継承を規範化しており、第二のパラメータを受け入れることができます.
        ...
        var man3 = Object.create(person)
        console.log(man3.name) // 'seven'
        console.log(man3.friends) // ['blob', 'micelid']      1   friends
    
        var man4 = Object.create(person, { 
          name: { 
            value: 'james' 
          } 
        })
        console.log(man4.name) // 'james'
        console.log(man4.friends) // ['blob', 'micelid']      1   friends
    
    3.寄生式継承(値タイプ継承)
    カスタムタイプやコンストラクタではなく、主にオブジェクトを考慮して使用すると、プロトタイプ継承の考えでオブジェクトが強調されます(サブオブジェクトに属性が追加されます).
        function createAnother (original) {
          //        
          var clone = Object(original)
          //           ,    
          clone.sayHi = function() {
            console.log('Hi')
          }
          return clone
        }
        var another = createAnother(person)
        another.sayHi() // 'Hi'
    
    4.寄生結合式継承(引用タイプは理想の継承モデルを継承)
    コンビネーション継承モードでは、マンインスタンスを作成するごとに、Person()を2回呼び出します.一度はMan()の内部で、サブタイプの原型オブジェクトを一度に指定する場合:
        ...
        //    
        function Sub (name, age) {
          //           ,    
          Super.call(this, name) // -----------     SuperType
          this.age = age
        }
    
        //               ,      constructor           
        //     
        Sub.prototype = new Super() // --------------     SuperType
        //        constructor    
        Sub.prototype.constructor = Sub
        ...
    
    寄生結合式は構造関数の継承属性を借用し、プロトタイプチェーンの混成形式の継承方法を継承し、結合継承を解決するために二次構成関数を呼び出す必要がある問題を解決します.
        //                          constructor     
        function inheritPrototype (SubType, SuperType) {
    
          //         
          var prototype = Object(SuperType.prototype)
          
          //       constructor       
          prototype.constructor = SubType
    
          //             
          SubType.prototype = prototype
        }
    
        //    
        function SuperType (name) {
          this.name = name
        }
        SuperType.prototype.sayName = function() {
          console.log(this.name)
        }
        
        //    
        function SubType (name, age) {
          //     
          SuperType.call(this, name)
          this.age = age
        }    
    
        //                   
        inheritPrototype(SubType, SuperType)
    
        //          
        SubType.prototype.sayAge = function () {
          console.log(this.age)
        }
    
        var sub1 = new SubType('lee', 18)
        sub1.sayName() // ’lee'
        sub1.sayAge() // 18
    
        var sub2 = new SubType('liu', 28)
        sub2.sayName() // 'liu'
        sub2.sayAge() // 28
    
    JavaScriptの継承は全部で四つの方式があります.必要に応じて使えます.
  • 似たようなオブジェクトを作成することだけを考慮した場合、継承値の種類は、プロトタイプ継承を使用することを推奨する.引用の種類を引き継ぐ必要があります.寄生式で
  • を継承することを提案します.
  • 参照タイプを継承する完全な継承モデルは、結合継承寄生結合式継承よりも効率的であるべきである(親タイプの構造関数を呼び出す回数を減らす)
  • .
    終了
    ps:深セン南山区求職中…クリックして履歴書を確認してください.