JavaScript 如何实现继承?

 

1.原型链继承

function Parent () {this.name = 'aa';}

Parent.prototype.getName = function () {

    console.log(this.name);

}

function Child () {}

Child.prototype = new Parent();

var child = new Child();

console.log(child.getName()) // aa

特点:

  1. 非常纯粹的继承关系,实例是子类的实例,也是父类的实例
  2. 父类新增原型方法/原型属性,子类都能访问到
  3. 简单,易于实现

缺点:

  1. 要想为子类新增属性和方法,必须要在new Child()这样的语句之后执行,不能放到构造器中
  2. 无法实现多继承
  3. 来自原型对象的引用属性被所有实例共享
  4. 创建子类实例时,无法向父类构造函数传参

2.构造函数继承 

    function a2() {this.color=[1,2,3,4];  }

    function b2() {a2.call(this);  }


    var instance2=new b2();

    instance2.color.push(5);

    console.log(instance2.color);//[1, 2, 3, 4, 5]


    var instance3=new b2();

    console.log(instance3.color);//[1, 2, 3, 4]

    //上面两个例子主要想指出,instance2对构造函数的数组做修改是不会影响到其他的实例,
    //因为它改的是属于它自己的那一份,不像原型那样大家共享


    //------------------------//


    function a3(name) { this.name=name; }


    function b3() {a3.call(this,"ww");this.age=29;  }


    var instance4=new b3();

    console.log(instance4.name);//ww

    console.log(instance4.age);//29

    //这个例子说明构造函数继承可以传参数

特点:

  1. 解决了原型链继承中,子类实例共享父类引用属性的问题
  2. 创建子类实例时,可以向父类传递参数
  3. 可以实现多继承(call多个父类对象)

缺点:

  1. 实例并不是父类的实例,只是子类的实例
  2. 只能继承父类的实例属性和方法,不能继承原型属性/方法
  3. 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能

3.组合继承

    function a4(name) {this.name=name;this.color=[1,2,3,4];  }

    a4.prototype.sayName=function(){console.log(this.name);}


    function b4(name,age) { a4.call(this,name);this.age=age; }

    b4.prototype=new a4();

    b4.prototype.constructor=b4;

    b4.prototype.sayAge=function(){console.log(this.age);}


    var instance5=new b4("aa",12);

    instance5.color.push(5);

    console.log(instance5.color);//[1, 2, 3, 4, 5]

    instance5.sayAge();//12

    instance5.sayName();//aa


    var instance6=new b4("bb",22);

    console.log(instance6.color);//[1, 2, 3, 4]

    instance6.sayName();//bb

    instance6.sayAge()//22


    var instance5=new a4("aa");

    instance5.sayAge();// not  a  function
    //这个输出说明b4.prototype=new a4(),然后b4.prototype.sayAge增加了prototype的方法,但是 
    //增加的方法并没有增加到a4上面

特点:

  1. 弥补了构造继承的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法
  2. 既是子类的实例,也是父类的实例
  3. 不存在引用属性共享问题
  4. 可传参
  5. 函数可复用

缺点:

调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)

4.原型式继承

    function object(o){

        function F(){};

        F.prototype=o;

        return new F();

    }


    var person={name:"wwwwwww",age:[1,2,3]};


    var anp=object(person);

    anp.name="er";

    anp.age.push(99);


    var ynp=object(person);

    ynp.name="ll";

    ynp.age.push(100);


    console.log(person.age);//[1, 2, 3, 99, 100]
    //输出结果说明属性共享这一问题


    //----------------//

    var person2={name:"wwwwwww",age:[1,2,3]};


    var anp=Object.create(person2);

    anp.name="er";

    anp.age.push(99);


    var ynp=Object.create(person2);

    ynp.name="ll";

    ynp.age.push(100);


    console.log(person2.age);//[1, 2, 3, 99, 100]
    //这里说明用create方法一样可以完成原型式继承

 

 缺点也是来自原型对象的引用属性被所有实例共享

  5.寄生式继承   

 function createAnother(original) {

        var clone=object(original);

        clone.sayHi=function(){  //扩充了方法

            console.log("hi");

        };

        return clone;

      }


      var per={name:"loud",age:[1,2,3]};

      var pp=createAnother(per);

      pp.sayHi();

缺点和构造函数继承一样,都是每次创建对象都会创建一遍方法,内存占用大

6.寄生组合式继承 

   function inheritPrototype(b5,a5) {

        var prototype=object(a5.prototype);

        prototype.constructor=b5;

        b5.prototype=prototype;

     }


     function a5(name) {

         this.name=name;

         this.color=[1,2,3];

     }


     a5.prototype.sayName=function(){

         console.log(this.name);

     }


     function b5(name,age) {

         a5.call(this,name);

         this.age=age;

    }


    inheritPrototype(b5,a5);


    b5.prototype.sayAge=function(){

       console.log(this.age);

    }


    var instance7=new b5("dd",99);

    instance7.sayName();

原型链大概是这样:其实寄生组合继承我觉得可以理解为组合继承的改进,和组合继承相比,避免了new a5()的写法,同时又保持了原型继承关系

特点:

只调用了一次构造函数,并且避免了在 prototype 上面创建不必要的、多余的属性。与此同时,原型链还能保持不变;因此,还能够正常使用 instanceof 和 isPrototypeOf。开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。

缺点:代码比较复杂

参考文档:JS继承的实现方式

猜你喜欢

转载自blog.csdn.net/loisandyu/article/details/83046950