JS進階(二)(原型鏈,繼承)

原型及原型鏈

  • 原型鏈:是一種關係,實例對象和原型對象之間的關係,關係經過原型(proto)來聯繫的。
    • 實例對象的原型__proto__指向的是該對象所在的構造函數的原型對象
    • 構造函數的原型對象(prototype)指向若是改變了,實例對象的原型(proto)指向也會改變
    • 實例對象和原型對象之間的關係是通__proto__原型來聯繫起來的,這個關係就是原型鏈。
    //A的構造函數
      function A(){}
      //A的原型對象方法
      A.prototype.a = function(){
          consloe.log("A的原型方法");
      }
      //B的構造函數
      function B(){}
      //B的原型對象方法
      B.prototype.b = function(){
          console.log("B的原型方法");
      }
      //B的原型,指向了A的實例對象(改變原型指向 )
      B.prototype = new A();
      var bObj = new B();
      bObj.b();//bObj.b is not a function
      bObj.a();//A的原型方法
    複製代碼
  • 實例對象的__proto__指向的是該實例對象所在的構造函數的原型對象prototype,該原型對象prototype的__proto__指向的是構造函數Object的原型對象prototype,Object的原型對象prototype的__proto__指向的是null
    function Person(){
            
        }
        var per = new Person();
    複製代碼
    • per實例對象的__proto__--->Person.prototype.proto--->Object.prototype的__proto__是null
  • 若是原型指向改變了,那麼應該在原型改變指向以後添加原型方法(以前添加的失效)
  • 實例對象訪問這個屬性,應該先從實例對象中找,找不到就去指向的原型對象中找,若在原型對象中找不到則爲undefined(不會報錯是由於對象.屬性名字的時候就已經建立了由於js是一門動態類型的語言)
  • 實例對象不能改變原型對象的屬性值,原型對象中的屬性值直接經過原型對象.屬性=值來改變
  • 原型鏈例子
    <body>
       <div id="dv"></div>
       <script>
         var divObj=document.getElementById("dv");
         console.dir(divObj);
       
         /*divObj.__proto__---->HTMLDivElement.prototype的__proto__
         --->HTMLElement.prototype的__proto__---->Element.prototype的__proto__
         ---->Node.prototype的__proto__---->EventTarget.prototype的__proto__
         ---->Object.prototype沒有__proto__,因此,Object.prototype中的__proto__是null
         */
       
       </script>
    </body>
    複製代碼

實現繼承:

  • 面向對象特性: 封裝,繼承,多態
  • 繼承:
    • 首先繼承是一種關係,類(class)與類之間的關係,面向對象語音的繼承是爲了多態服務的,JS變速面向對象的語言,但能夠經過構造函數模擬類,而後經過原型來模擬實現繼承
    • 繼承也是爲了數據共享,JS中的繼承也是爲了實現數據共享
    • 1.原型做用之一:數據共享,節省內存空間---2.原型做用之二:爲了實現繼承
    • 相同的代碼太多,形成了代碼的冗餘(重複的代碼)
    1. 原型實現繼承---經過原型來繼承,只需改變構造函數的原型對象的指向便可
      • 缺陷:由於改變原型指向的同時實現繼承,直接初始化了屬性,繼承過來的屬性的值都是同樣的,只能從新調用對象的屬性進行賦值
    2. 借用構造函數實現繼承---構造函數名字.call(當前對象,屬性,屬性···)
      function A(name,age,sex){
            this.name = name;
            this.age = age;
            this.sex = sex;
        }
        A.prototype.a = function(){
            console.log("這是A的原型方法");
        }
        
        function B(name,age,sex,weight){
            //借用構造函數
            Person.call(this,age,sex);
            this.weight = weight;
        }
        var b = new B("小B",18,"男","55kg");
        console.log(b.name,b.age,b.sex,b.weight);//小B 18 男 55kg
        console.log(b.a());//報錯
      複製代碼
      • 解決了屬性繼承,而且值不重複的問題
      • 缺陷: 父級類別中的方法不能繼承
    3. 組合繼承---原型集成+借用構造函數繼承
      function A(name,age,sex){
                  this.name = name;
                  this.age = age;
                  this.sex = sex;
              }
              A.prototype.a = function(){
                  console.log("這是A的原型方法");
              }
              
              function B(name,age,sex,weight){
                  //借用構造函數:屬性值重複的問題
                  Person.call(this,age,sex);
                  this.weight = weight;
              }
              //改變原型指向---繼承
              B.prototype = new A();//不傳值======
              var b = new B("小B",18,"男","55kg");
              console.log(b.name,b.age,b.sex,b.weight);//小B 18 男 55kg
              b.a();//這是A的原型方法
      複製代碼
    4. 拷貝繼承: 把一個對象中的屬性或者方法直接複製到另外一個對象中
      function A(){
            
              }
              A.prototype.name = "小A";
              A.prototype.age = 18;
              A.prototype.a = function(){
                  console.log("這是A的原型方法");
              }
              var b = {};
              for(var key in A.prototype){
                  b[key] = A.prototype[key];
              }
              console.log(b);//{name:"小A",age:18,a:f}
              b.a();//這是A的原型方法
      複製代碼

------------------------------------------------------記錄於 2019.4.24 JavaScript高級(二)bash

相關文章
相關標籤/搜索