js继承方式

原型链继承

// 父类
function Parent(name) {
    this.name = name;
}

Parent.prototype.age = 20; // 在父类原型上添加属性

// 子类
function Per() {
    this.name = 'Rory';
}

Per.prototype = new Parent();
const per = new Per();
console.log(per)

打印结果如下:

原型链继承

上面定义了一个 Parent 类并传了一个 name 值,而且在 Parent 的原型上添加了一个 age 属性,然后定义了一个子类 Per,并将子类的原型设置为 Parent 的实例,这种方式是利用原型来实现继承,它就是让新实例的原型等于父类的实例。这种继承方式可继承的属性有:

  • 实例的构造函数的属性
  • 父类构造函数的属性,比如 Parentname
  • 父类原型的属性 比如 age

缺点:

  • 无法向父类构造函数传参,比如上图中新实例的原型中的 nameundefined
  • 所有新实例都共用父类的属性,如果一个实例修改了原型会影响其它的实例

构造函数继承

// 父类
function Parent(name) {
    this.name = name;
}
Parent.prototype.age = 20; // 在父类原型上添加属性

function Per() {
    Parent.call(this, 'Rory');
    this.sex = '男';
}

const per = new Per();
console.log(per)

打印结果如下

构造函数继承

构造函数继承使用了 call()apply() 将父类构造函数引入子类函数,这种继承方式的特点有:

  • 只继承父类构造函数的属性,没有继承父类原型上的属性
  • 解决了原型链继承的缺点
  • 可以继承多个构造函数
  • 在子类的实例中可以传入父类的实例参数

缺点:

  • 只能继承父类构造函数的属性
  • 每次使用都得重新调用,无法复用
  • 每个新实例都有父类构造函数的属性,会比较臃肿

组合式继承

// 父类
function Parent(name) {
    this.name = name;
}

Parent.prototype.age = 20; // 在父类原型上添加属性

function Per(name) {
    Parent.call(this, name);
}

Per.prototype = new Parent();

const per = new Per('Rory');

console.log(per);

打印结果如下:

组合式继承

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

缺点:

  • 调用了两次父类构造函数,所以会比较耗内存
  • 子类的构造函数会代替原型上的那个父类构造函数。

原型式继承

// 父类
function Parent(name) {
    this.name = name;
}

Parent.prototype.age = 20; // 在父类原型上添加属性

// 封装一个函数
function content(obj) {
    function F(){};
    F.prototype = obj;
    return new F();
}

const p = new Parent('Rory');
const per = content(p);

console.log(per);
console.log(per.name);
console.log(per.age);

打印结果如下:

原型式继承

这种继承方式是先定义一个函数 content,然后在内部定义一个构造函数 F,将该构造函数的原型设置为传入的参数,参数是一个对象,然后将 F 实例化后返回。

缺点:

  • 所有实例都会继承原型上的属性
  • 无法复用,返回的是一个实例,属性要另外添加

寄生式继承

// 父类
function Parent(name) {
    this.name = name;
}

Parent.prototype.age = 20; // 在父类原型上添加属性

// 封装一个函数
function content(obj) {
    function F(){};
    F.prototype = obj;
    return new F();
}

const Per = new Parent();

function subObject(obj) {
    const per = content(obj);
    per.name = 'Rory';
    return per;
}

const p = subObject(Per);

console.log(p);

打印结果如下:

寄生式继承

这种继承方式相当于给原型式继承外面套了个壳子,可以在 subObject 里新增属性或方法

优点:

  • 没有创建自定义类型,因为只是套了个壳子返回对象,这个函数就成了创建的新对象

缺点:

  • 没用到原型,无法复用

寄生组合式继承

// 父类
function Parent(name) {
    this.name = name;
}

Parent.prototype.age = 20; // 在父类原型上添加属性

function content(obj) {
    function F(){}
    F.prototype = obj;
    return new F();
}

const Per = content(Parent.prototype);

function subObject() {
    Parent.call(this, 'Rory');
}

subObject.prototype = Per;
Per.constructor = subObject; // 修复实例
const p = new subObject();
console.log(p)

打印结果如下:

寄生组合式继承

这种继承方式修复了组合继承的问题,在函数内返回对象然后调用,函数的原型等于另一个实例。在函数中用 apply 或者 call 引入另一个构造函数,可传参

特点:

  • 可以向父类传参
  • 子类实例可以继承到父类原型上的属性
  • 可以复用

ES6中的继承

通过 class 定义一个类,再用 extends 进行继承,通过 super 继承父类的属性或方法

class Parent {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    drink() {
        console.log('喝水')
    }
}

class Per extends Parent {
    constructor(name, age, sex) {
        super(name, age);
        this.sex = sex;
    }
    drink() {
        super.drink();
    }
}

const p = new Per('Rory', 22, '男');
console.log(p)

打印结果如下:

ES6继承

你可能感兴趣的:(js继承方式)