js继承的几种方法和es6继承方法


继承方法

  • 原型链继承
  • 构造函数继承
  • 实例继承
  • 组合继承
  • 原型式继承
  • 寄生式继承(原型式+工厂模式 )
  • ES6的继承


原型链继承

1.基本思想

利用原型链来实现继承,超类的一个实例作为子类的原型

2、具体实现

function F() {}

    //原型属性,原型方法:

    F.prototype.name="Lee";

    F.prototype.age=33;

    F.prototype.run=function(){

        return this.name+" "+this.age+" running";

    }

    var f = new F();

    console.log(f.name);

    console.log(f.run);

3.优缺点

1)优点

  • 简单明了,容易实现
  • 实例是子类的实例,实际上也是父类的一个实例
  • 父类新增原型方法/原型属性,子类都能访问到

2)缺点

  • 所有子类的实例的原型都共享同一个超类实例的属性和方法
  • 无法实现多继承
  • 在创建子类的实例时 不能向父类的构造函数传递参数

构造函数继承

1。基本思想

通过使用call、apply方法可以在新创建的对象上执行构造函数,用父类的构造函数来增加子类的实例

2、具体实现

function F() {

        // 属性

        this.name = name || 'dragon';

        // 实例方法

        this.sleep = function(){

            console.log(this.name + '正在睡觉!');

        }

    }

    function C(name){

        F.call(this);

        this.name = name || 'Tom';

    }

    var c=new C()

    console.log(c.name);

    console.log(c.sleep());

3.优缺点

1)优点

  • 简单明了,直接继承超类构造函数的属性和方法

2)缺点

  • 无法继承原型链上的属性和方法

实例继承

1.基本思想

为父类实例添加新特性,作为子类实例返回

2.具体实现

function F() {

        // 属性

        this.name = name || 'Animal';

        // 实例方法

        this.sleep = function(){

            console.log(this.name + '睡觉');

        }

    }

    function C(name){

        var instance = new F();

        instance.name = name || 'Tom';

        return instance;

    }

    var c = new C();

    console.log(c.name);

    console.log(c.sleep());

3.优缺点:
1)缺点:

  • 不限制调用方式,不管是new 子类()还是子类(),返回的对象具有相同的效果

2)缺点:

  • 实例是父类的实例,不是子类的实例
  • 不支持多继承

组合继承

1.基本思想

利用构造继承和原型链组合

2.具体实现

function F() {

        // 属性

        this.name = name || 'Animal';

        // 实例方法

        this.sleep = function(){

            console.log(this.name + '正在睡觉!');

        }

    }

    function C(name){

        F.call(this);//构造函数继承

        this.name = name || 'Tom';

    }

    C.prototype = new F();//原型继承

    var q=new C();

    console.log(q.name);

    console.log(q.sleep());

3.优缺点

1)优点

  • 解决了构造继承和原型链继承的两个问题

2)缺点

  • 实际上子类上会拥有超类的两份属性,只是子类的属性覆盖了超类的属性

原型式继承

1.基本思想

采用原型式继承并不需要定义一个类,传入参数obj,生成一个继承obj对象的对象

2、具体实现

var obj = {
       name: "qw",
        age: "12",
        ada:"asd"
    }

    function F(o) {

        function C() {}

        C.prototype = o;

        return new C();
    }
   var q= F(obj)

    console.log(q.name);

    console.log(q.age);

3.优缺点

1)优点:

  • 直接通过对象生成一个继承该对象的对象

2)缺点:

  • 不是类式继承,而是原型式基础,缺少了类的概念

寄生式继承(原型式+工厂模式 )

原型式+工厂模式
解决了组合继承两次调用构造函数的问题

1.基本思想

创建一个仅仅用于封装继承过程的函数,然后在内部以某种方式增强对象,最后返回对象

2、具体实现

//临时中转函数

    function obj(o) {

        function F() {}

        F.prototype = o;

        return new F();

    }

    //寄生函数

    function create(o){

        var q= obj(o);

        //可以对f进行扩展

        q.sleep = function(){

            return this.name+”睡觉”;

        }

        return q;

    }

    var box = {

        name: 'Lee',

        age: 100,

        family: ['Dad', 'Mom', 'Sister']

    };

    var box1 = create(box);

    alert(box1.name);

    alert(box1.run());

3.优缺点
1)优点:

  • 原型式继承的一种拓展

2)缺点:

  • 依旧没有类的概念
//临时中转函数

    function obj(o) {

        function F() {}

        F.prototype = o;

        return new F();

    }

    //寄生函数

    function create(box,desk){

        var q = obj(box.prototype);

        q.construtor=d;

        d.prototype=q;

    }

    function B(name,age){

        this.name=name;

        this.age=age;

    }

    B.prototype.run=function(){

        return this.name + " " + this.age +  " running..."

    }

    function D(name,age){

        Box.call(this,name,age);

    }

//通过寄生组合继承来实现

create(B,D);//替代D.prototype=new B();
 
    var d= new D('Lee',100);

    alert(d.run());

3.优缺点

1)优点:

完美实现继承,解决了组合式继承带两份属性的问题

2)缺点:

过于繁琐,故不如组合继承

ES6的继承

通过extends关键字

class father{

        constructor(name){

            this.name=name

            this.names=[1,2,3]

        }

        getname(){

            console.log(this.name);

        }

    }

    class child extends father{

        constructor(name){

            super(name);

        }

        sayHello(){

            console.log("sayHello");

        }

        static hh(){

            console.log("hh")

        }

    }

    var cc=new child("juanjuan");

    cc.sayHello();

    cc.getname();  //juanjuan

    child.hh();  //hh

    cc.names.push("wqwq");

    var c1=new child("sasasa");

    console.log(c1.names)  //[1,2,3]