JS中的继承

ES5的继承

以下,我们假设父类为Animal,拥有name和age属性,以及run方法。同时设子类为Dog。Animal类的构造函数代码如下:

 function Animal(name,age){
    this.name=name;
    this.age=age;
  }
  Animal.prototype.run=function(){
    console.log(this.name+'is running')
  }

法1:构造函数继承

子类中,利用函数的call,apply以及bind的方法,将父类构造函数中的this指向自身。以call为例,具体代码如下:

  function Dog(name,age){
    Animal.call(this,name,age);
  }

实例化Dog子类,并打印输出该实例,接着调用该实例的run方法,代码以及结果如下:

  const dog1=new Dog('Jack',7);
  console.log(dog1);
  dog1.run();

此时会发现,该实例的属性名称得到继承,并根据其构造函数实参而设为了对应的值。但是发现子类实例化对象没有父类的run方法,这说明通过引用构造函数继承时,子类仅得到父类的属性,而并未继承得到父类的方法。(此处方法都写入构造函数的prototype中,如果方法作为构造函数的属性值,则能继承该方法)

法2:原型继承

 将子类的prototype指向父类的实例化对象。具体代码如下:

function Dog(name, age) {

}
Dog.prototype = new Animal();

实例化Dog子类,并打印输出该实例,接着调用该实例的run方法,代码如下:

const dog1 = new Dog('Bob', 10);
console.log(dog1)
dog1.run();

 此时可以发现,通过原型继承结果仅继承了父类的方法,而无法拿到父类的属性名。这与构造函数继承结果恰恰相反。实参只能写入父类实例化对象中才可获取到对应属性的值,但此时的属性与属性值也不是子类实例化对象自身的属性与属性值。

法3:组合继承

通过观察构

造函数继承与原型继承可以发现,二者继承内容互补,那么同时运用这两种继承方法,就可以同时拿到父类的属性与方法了。具体代码如下:

function Dog(name,age) {
    Animal.call(this,name,age);
}
Dog.prototype=new Animal();

实例化Dog子类,并打印输出该实例,接着调用该实例的run方法,代码以及结果如下:

    const dog1 = new Dog('Amy', 9);
    console.log(dog1)
    dog1.run();

通过运行结果可以看到,虽然通过组合继承能拿到父类的属性与方法,但在继承父类方法的同时又一次继承了父类的属性,造成了不必要的赘余。 

法4:寄生继承

通过调用Object的create方法,该方法实参为父类的prototype,并将这个新生成的对象赋给子类的prototype属性。(注:prototype本质上是一个对象)具体代码如下:

function Dog(name,age) {
    Animal.call(this,name,age);
}
Dog.prototype=Object.create(Animal.prototype);

 实例化Dog子类,并打印输出该实例,接着调用该实例的run方法,代码以及结果如下:

const dog1 = new Dog('Tom', 5);
console.log(dog1)
dog1.run();

 可以发现此时相较于组合继承,赘余的父类属性消失。

ES6的继承

 ES6的继承使用extends关键字实现。此处仍以Animal为父类,Dog为子类。具体代码如下:

class Animal {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    run = function () {
        console.log(this.name + " is running")
    }
}

class Dog extends Animal {
}

实例化Dog子类,并打印输出该实例,接着调用该实例的run方法,代码以及结果如下:

const dog=new Dog('Ken',7);
console.log(dog)
dog.run()

 super关键字与重写

1.如果子类用的是自己的构造函数,则需要使用super关键字调用父类的构造函数。

子类创建的代码如下:

class Dog extends Animal {
    constructor(name,age,weight){
        super(name,age);
        this.weight=weight;
    }
}

 实例化Dog子类,并打印输出该实例,接着调用该实例的run方法,代码以及结果如下:

const dog=new Dog('Jane',11,'5kg');
console.log(dog)
dog.run()

 如果不使用super关键字,则会报错,提示必须使用super构造函数:

 2.如果子类拥有自己的方法,且该方法与父类某个方法同名,则调用该方法时会调用子类的方法而非父类的方法,这就叫方法的重写

子类创建的代码如下:

class Dog extends Animal {
    constructor(name,age){
        super(name,age)
    }
    run=function(){
        console.log(this.name + " has run")
    }
}

 实例化Dog子类,并打印输出该实例,接着调用该实例的run方法,代码以及结果如下:

const dog=new Dog('John',4);
console.log(dog)
dog.run()

3.如果子类想调用父类的方法,则需要使用super关键字。

 子类创建的代码如下:

class Dog extends Animal {
    constructor(name,age){
        super(name,age)
    }
    run(){
        super.run()
    }
}

实例化Dog子类,并打印输出该实例,接着调用该实例的run方法,代码以及结果如下:

const dog=new Dog('Mike',5);
console.log(dog)
dog.run()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值