ES5中的继承和ES6中的类继承模式详解

  • Post author:
  • Post category:其他




ES5继承



1. 原型链继承

function Zoo() {
    this.zoo = '动物园';
}

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

panda.prototype = new Zoo();

var animal = new panda('熊猫');
console.log(animal.zoo + '里面有一只' + animal.name);


缺点:

不能向父类构造函数(Zoo)传递参数



2. 构造函数继承

——在子类型构造函数的内部调用父类构造函数,使用

apply()



call()

方法将this指向子类

function Zoo(zoo) {
    this.zoo = zoo;
}

function panda(zoo, name) {
    Zoo.call(this,zoo); // 把 Zoo的this 指向panda
    this.name = name;
}

var animal = new panda('动物园','熊猫');
console.log(animal.zoo + '里面有一只' + animal.name);


缺点:

无法调用父类原型上的方法 例如:

Zoo.prototype.sleep = function() {
    console.log('要睡觉觉了!');
}

console.log(animal.sleep()); // TypeError: animal.sleep is not a function



3. 组合继承

——将原型链继承和构造函数继承组合到一起。使用原型链继承实现对原型属性和方法的继承,用借用构造函数继承实现对父实例属性的继承。这样既通过在原型上定义方法实现了函数复用,又能保证每个实例都有自己的属性

function Zoo(zoo) {
    this.zoo = zoo;
}

Zoo.prototype.sleep = function() {
    console.log('要睡觉觉了!');
}

function panda(zoo, name) {
    Zoo.call(this,zoo); // 把 Zoo的this 指向panda
    this.name = name;
}

panda.prototype = new Zoo();
var animal = new panda('动物园','熊猫');
console.log(animal.zoo + '里面有一只' + animal.name);
animal.sleep()


缺点:

会调用两次超类型构造函数,一次是在创建子类型原型的时候,一次是在子类型构造函数的内部,占用内存。



4. 寄生组合式继承

——寄生组合式继承是对组合继承的进一步优化。我们先看一下为什么要写这个语句。

panda.prototype = new Zoo();


我们无非是想让panda继承Zoo的原型。但是我们为什么不直接写成这样呢?

panda.prototype = Zoo.prototype

——这样写确实可以实现子类对象对父类对象原型的继承。但是这样写的话:所有继承该父类的子类对象的原型都指向同一个了。也就是说SubType不能有自己的原型了。这显然不是我们想要的。

——既然不能直接继承,那可不可以间接继承Zoo.prototype呢。这就是最终的解决方案:间接组合式继承。

——我们让一个对象去指向Zoo.prototype,然后让panda.prototype指向这个函数产生的对象不就可以了嘛。

——核心函数:

 function indirect(son, father) {
    var target = Object.create(father.prototype); // 也可以直接写var target = father.prototype; father.prototype本身就是一个对象,万物皆对象
    target.constructor = son;
    son.prototype = target;
}

function Zoo(zoo) {
    this.zoo = zoo;
}

Zoo.prototype.sleep = function() {
    console.log('要睡觉觉了!');
}

function panda(zoo, name) {
    Zoo.call(this,zoo); // 把 Zoo的this 指向panda
    this.name = name;
}

indirect(panda,Zoo);
var animal = new panda('动物园','熊猫');
console.log(animal.zoo + '里面有一只' + animal.name);
animal.sleep()


优点:

只调用了一次Zoo构造函数,因此避免在panda.prototype上创建不必要的,多余的属性,与此同时,原型链还能保持不变,还能正常使用instanceof 和isPrototypeOf(),因此,寄生组合式继承被认为是引用类型最理想的继承范式。



ES6 继承

class Zoo {
    constructor(zoo) {
        this.zoo = zoo;
    }
    sleep() {
        return '要睡觉觉了!';
    }
}

class animal extends Zoo {
    constructor(zoo,age) {
        super(zoo);
        this.age = age;
    }
    eat() {
        console.log('吃完饭饭'+super.sleep()); // 这里的super指代的是父亲构造函数 Zoo 的原型上的方法 Zoo.prototype
    }
}

var panda = new animal('上野动物园','5');

console.log(panda.zoo);// 上野动物园
panda.eat();// 吃完饭饭要睡觉觉了!

——Class 可以通过extends关键字实现继承

——子类必须在constructor方法中调用super方法,否则新建实例时会报错。

——这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象。

——

super(zoo)

里的参数zoo 是父亲的属性 要是用父类属性需要加上参数



版权声明:本文为alokka原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。