Skip to content

实现继承的7种方式

发表于
更新于
阅读量

JS是一门弱类型动态语言,封装和继承是他的两大特性

原型链继承

将父类的实例作为子类的原型

定义父类

javascript
// 定义一个动物类
function Animal(name){
    // 属性
    this.name = name || 'Animal'
    // 实例方法
    this.sleep = function(){
        console.log(this.name + '正在睡觉!')
    }
}

// 原型方法
Animal.prototype.eat = function(food){
    console.log(this.name + '正在吃:' + food)
}

子类:

javascript
function Cat(){}

Cat.prototype = new Animal()
Cat.prototype.name = 'cat'

//TestCode
var cat = new Cat()
console.log(cat.name) // cat
console.log(cat.eat('fish')) // cat正在吃:fish 
console.log(cat.sleep()) // cat正在睡觉! 
console.log(cat instanceof Animal) // true
console.log(cat instanceof Cat) // true

优缺点:简单易于实现,但是要想为子类新增属性和方法,必须要在new Animal()这样的语句后执行,无法实现多继承

构造继承

实质是利用call来改变Cat中的this指向

javascript
function Cat(name){
    Animal.call(this)
    this.name = name || 'Tom'
}

优缺点:可以实现多继承,不能继承原型属性/方法

实例继承

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

javascript
function Cat(name){
    var instance = new Animal()
    instance.name = name || 'Tom'
    return instance
}

优缺点:不限制调用方式,但不能实现多继承

拷贝继承

将父类的属性和方法拷贝一份到子类中

javascript
function Cat(name){
    var animal = new Animal()
    for(var p in animal){
        Cat.prototype[p] = animal[p]
    }
    Cat.prototype.name = name || 'Tom'
}

优缺点:支持多继承,但是效率低占用内存

组合继承

通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用

javascript
function Cat(name){
    Animal.call(this)
    this.name = name || 'Tom'
}
Cat.prototype = new Animal()
Cat.protptype.constructor = Cat

寄生组合继承

javascript
function Cat(name){
    Animal.call(this)
    this.name = name || 'Tom'
}
(function(){
    // 创建一个没有实例方法的类
    var Super = function(){}
    Super.prototype = Animal.prototype
    // 将实例作为子类的原型
    Cat.prototype = new Super()
})()

ES6的extends继承

ES6 的继承机制是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this

javascript
// 父类
class Person{
    // constructor是构造方法
    constructor(skin,language){
        this.skin = skin
        this.language = language
    }
    say(){
        console.log('我是父类')
    }
}

// 子类
class Chinese extends Person{
    constructor(skin,language,position){
        //console.log(this);//报错
        super(skin, language);
        //super();相当于父类的构造函数
        //console.log(this);调用super后得到了this,不报错,this指向子类,相当于调用了父类.prototype.constructor.call(this)
        this.positon = positon;
    }
    aboutMe() {
        console.log(`${this.skin} ${this.language}  ${this.positon}`);
    }
}


//调用只能通过new的方法得到实例,再调用里面的方法
let obj = new Chinese('红色', '中文', '香港');
obj.aboutMe();
obj.say();

Released under the MIT License.