JS中5種經典繼承方式


繼承

JS中繼承的概念:

  • 通過【某種方式】讓一個對象可以訪問到另一個對象中的屬性和方法,我們把這種方式稱之為繼承 並不是所謂的xxx extends yyy

為什么要使用繼承?

  • 有些對象會有方法(動作、行為),而這些方法都是函數,如果把這些方法和函數都放在構造函數中聲明就會導致內存的浪費
    function Person(){
        this.say=function(){
            console.log("你好")
        }
    }
    var p1=new Person();
    var p2=new Person();
    console.log(p1.say === p2.say);   //false

繼承的第一種方式:原型鏈繼承1

    Person.prototype.say=function(){
        console.log("你好")
    }
  • 缺點:添加1、2個方法無所謂,但是如果方法很多會導致過多的代碼冗余

繼承的第二種方式:原型鏈繼承2

    Person.prototype = {
        //切記不能忘記
        constructor:Person,
        say:function(){
            console.log("你好");
        },
        run:function(){
            console.log("正在進行百米沖刺");
        }
    }
  • 注意點:
  • a、一般情況下,應該先改變原型對象,再創建對象
  • b、一般情況下,對於新原型,會添加一個constructor屬性,從而不破壞原有的原型對象的結構

繼承的第三種方式:拷貝繼承(混入繼承:mixin)

  • 場景:有時候想使用某個對象中的屬性,但是又不能直接修改它,於是就可以創建一個該對象的拷貝
  • 實際運用:
    • jquery:$.extend:編寫jquery插件的必經之路
      • 基於jquery封裝一個表格控件
    var o1={ age:2 };

    var o2 = o1;
    o2.age=18;      
    //1、修改了o2對象的age屬性
    //2、由於o2對象跟o1對象是同一個對象
    //3、所以此時o1對象的age屬性也被修改了
    var o3={gender:"男",grade:"初三",group:"第五組",name:"張三"};
    var o4={gender:"男",grade:"初三",group:"第五組",name:"李四"};
    //上述代碼中,如果使用拷貝繼承對代碼進行優化會非常和諧

    //實現拷貝繼承:
    //1、已經擁有了o3對象
    //2、創建一個o3對象的拷貝(克隆):for...in循環
    

    //3、修改克隆對象,把該對象的name屬性改為"李四"
    
  • 實現1:
    var source={name:"李白",age:15}
    var target={};
    target.name=source.name
    target.age=source.age;
  • 淺拷貝和深拷貝

    • 淺拷貝只是拷貝一層屬性,沒有內部對象
    • 深拷貝其實是利用了遞歸的原理,將對象的若干層屬性拷貝出來
        var students=[
            {name:"",age:""},
            {name:"",age:""}
        ]
    
  • 上面的方式很明顯無法重用,實際代碼編寫過程中,很多時候都會使用拷貝繼承的方式,所以為了重用,可以編寫一個函數把他們封裝起來:

    function extend(target,source){
        for(key in source){
            target[key]=source[key];
        }
        return target;
    }
    extend(target,source)
  • 由於拷貝繼承在實際開發中使用場景非常多,所以很多庫都對此有了實現

    • jquery:$.extend
  • es6中有了 <對象擴展運算符> 仿佛就是專門為了拷貝繼承而生:

    • 優點:簡單的令人發指
    var source={name:"李白",age:15}
    //讓target是一個新對象,同時擁有了name、age屬性
    var target={ ...source }
    
    var target2={ ...source,age:18 }

繼承的第四種方式:原型式繼承:(道格拉斯在蝴蝶書中提出來的)

  • 場景:
    • a、創建一個純潔的對象:對象什么屬性都沒有
    • b、創建一個繼承自某個父對象的子對象
          var parent={ age:18,gender:"男"};
          var student=Object.create(parent);
          //student.__proto__===parent
      
  • 使用方式:
    • 空對象:Object.create(null)
        var o1={ say:function(){} }
        var o2=Object.create(o1);
    

繼承的第五種方式:借用構造函數實現繼承

  • 場景:適用於2種構造函數之間邏輯有相似的情況
  • 原理:函數的call、apply調用方式
function Animal(name,age,gender){
    this.name=name;
    this.age=age;
    this.gender=gender;
}
function Person(name,age,gender,say){
    this.name=name;
    this.age=age;
    this.gender=gender;

    this.say=function(){

    }
}
  • 局限性:Animal(父類構造函數)的代碼必須完全適用於Person(子類構造函數)

  • 以上代碼用借用構造函數實現

function Animal(name,age){
    this.name=name;
    this.age=age;
}
function Person(name,age,address){
    Animal.call(this,name);
    //this.name=name;
    //this.age=age;
    this.address=address;
}
  • 寄生繼承、寄生組合繼承...


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM