1. 程式人生 > >面向面試編程——javascript繼承的6種方法

面向面試編程——javascript繼承的6種方法

javascrip 復制 call bject object reat 常用 對象賦值 friends

javascript繼承的6種方法

1,原型鏈繼承

2,借用構造函數繼承

3,組合繼承(原型+借用構造)

4,原型式繼承

5,寄生式繼承

6,寄生組合式繼承

1.原型鏈繼承.

<script type="text/javascript">
    function Person(name,sex)
    {
        this.name=name;
        this.sex=sex;
        this.friends=[‘李四‘];
        this.getName=function(){
            alert(this.name);
        }
    }
   Person.prototype.id
=1; function Boy(age) { this.age=age; this.getAge=function(){ alert(this.age); } } //繼承 Boy.prototype=new Person("張三","男"); var boy=new Boy(16); alert(boy.name); //張三 boy.getAge(); //16 alert(boy.id); //
1 //屬性共享問題 console.log(boy.friends); //李四 var boy2=new Boy(17); boy2.friends.push(‘王五‘); //修改boy2的friends屬性的同時也影響了boy的屬性 console.log(boy.friends); //李四 王五 //驗證能否使用instanceof 和 isPrototypeof console.log(boy instanceof Person); //true console.log(Person.prototype.isPrototypeOf(boy)); //
true </script>

特點:既繼承了父類的模板,又繼承了父類的原型對象。

缺點:只能在父類設置一些參數,子類不能靈活傳參,不符合面向對象的思想,包含引用類型值的屬性始終都會共享相應的值。

2.借用構造函數繼承

<script type="text/javascript">
      //父類
    function Person(name,sex)
    {
        this.name=name;
        this.sex=sex;
        this.friends=[‘李四‘];
    }
    Person.prototype.id=1;
    //子類
    function Boy(name,sex,age)
    {

        //借用
        Person.call(this,name,age);

        this.age=age;
        this.getAge=function(){
            alert(this.age);
        }

    }


    var boy=new Boy("張三","男",16);
    alert(boy.name);  //張三

    boy.getAge();        //16

    alert(boy.id);  //undefined  沒有繼承父類的原型對象


    //屬性共享問題 ————不會有共享
  

    //驗證能否使用instanceof 和 isPrototypeof
    console.log(boy instanceof Person);                 //false
    console.log(Person.prototype.isPrototypeOf(boy));   //false
</script>

特點:只繼承了父類的模板,不繼承父類的原型對象。

缺點:方法都在構造函數中定義,不能做到函數復用。

3.組合繼承(原型+借用構造)最常用的繼承模式

<script type="text/javascript">
     //父類
    function Person(name,sex)
    {
        this.name=name;
        this.sex=sex;
        
    }
    Person.prototype.id=1;
    //子類
    function Boy(name,sex,age)
    {

        //借用構造函數  繼承父類的模板
        Person.call(this,name,age);

        this.age=age;
        this.getAge=function(){
            alert(this.age);
        }

    }
    
    //不傳遞參數,繼承父類的模板,繼承父類的原型對象 id 
    Boy.prototype=new Person();

    var boy=new Boy("張三","男",16);
    alert(boy.name);  //張三

    boy.getAge();        //16

    alert(boy.id);  //1


    //屬性共享問題 ————除了父類的原型對象,不會有共享
  

    //驗證能否使用instanceof 和 isPrototypeof
    console.log(boy instanceof Person);                 //true
    console.log(Person.prototype.isPrototypeOf(boy));   //true
</script>

特點:既繼承了父類的模板,又繼承了父類的原型對象。

缺點:做了3件事,繼承了父類兩次模板,繼承了一次原型對象

原型式繼承解決了這個問題

4.原型式繼承

<script type="text/javascript">
   var person={
    name:‘張三‘,
    sex:‘男‘,
    friends:[‘李四‘]
    }

    function object(obj)
    {
        function F(){}   //創建一個空的構造函數
        F.prototype=obj;  //將傳入的對象作為這個構造函數的原型
        return new F();   //返回一個新實例  對傳入的對象進行了一次淺復制
    }

    var boy=object(person);
    //ECMAScript 5 新增了Object.create()方法 與本例 object 方法行為相同
    //可改為 Object.create(person);

    alert(boy.name);  //張三

    //但是原型式同樣存在屬性共享的問題
    //例如:

    var girl=object(person);
    girl.friends.push(‘王五‘);

    alert(boy.friends); //李四 王五
    alert(girl.friends);//李四 王五

    //修改girl中的friends屬性  boy 也會受到影響
  

       //無法使用 instanceof 和 isPrototypeof
   
</script>

創造的目的是基於已有的對象創建新的對象,同時還不必因此創建自定義類型。

包含引用類型值的屬性始終都會共享相應的值,就像使用原型模式一樣。

5.寄生式繼承

<script type="text/javascript">
    function object(obj)
    {
        function F(){}   //創建一個空的構造函數
        F.prototype=obj;  //將傳入的對象作為這個構造函數的原型
        return new F();   //返回一個新實例  對傳入的對象進行了一次淺復制
    }

    function Person(person)
    {
        var clone=object(person);
        clone.getSex=function(){
            alert(this.sex);
        }
        return clone;
    }
    var person={
        name:‘張三‘,
        sex:‘男‘,
        friends:[‘李四‘]
    }
    var boy=Person(person);
    boy.getSex();         //



    //屬性共享問題————因為傳入同一個實例,所以存在共享問題
      var boy2=Person(person);
      boy2.friends.push(‘王五‘);
    
    alert(boy.friends);     //李四  王五

    
    //驗證能否使用instanceof 和 isPrototypeof
    console.log(boy instanceof Person);                 //false
    console.log(Person.prototype.isPrototypeOf(boy));   //false
</script>

與構造函數模式類似,不能做到函數復用會降低效率。

6.寄生組合式繼承

<script type="text/javascript">
    
    function object(o)
    {
        function F(){}
        console.log(o);
        F.prototype=o;
        return new F();

    }
    function extend(subType,superType)
    {
        var prototype=object(superType.prototype);  //創建父類的一個副本
        prototype.constructor=subType;                //為創建的副本添加失去默認的構造函數
        subType.prototype=prototype;                //將新創建的對象賦值給子類的原型
    }
    function Person(name)
    {
        this.name=name;
        this.friends=[‘李四‘];
    }
    function Boy(name,sex)
    {
        Person.call(this,name);             //借用構造函數  繼承父類的模板
        this.sex=sex;
    }

    extend(Boy,Person);  //繼承

    var boy=new Boy(‘張三‘,‘男‘);

    alert(boy.name);     //張三



    //屬性共享問題————不會存在共享問題
      var boy2=new Boy(‘張三‘,‘男‘);
      boy2.friends.push(‘王五‘);
    
    alert(boy.friends);     //李四


    //驗證能否使用instanceof 和 isPrototypeof
    console.log(boy instanceof Person);                 //false
    console.log(Person.prototype.isPrototypeOf(boy));   //false
</script>

寄生式組合繼承解決了組合繼承會調用兩次父類構造函數,子類最終會包含父類的全部實例屬性,父類的屬性不是必須的,子類的屬性會覆蓋父類的屬性。

寄生式組合繼承只調用一次父類構造函數,原型鏈能保持不變,因此還能夠正常使用instanceof和isPrototypeOf(),YUI的extend方法就使用的是寄生組合繼承,是實現基於類型繼承的最有效的方式。

面向面試編程——javascript繼承的6種方法