继承的多种方式

  1. 原型链继承

    即 子构造函数.prototype = new 父构造函数()
    // 创建父构造函数
    function SuperClass(){
        this.name = 'liyajie';
        this.age = 25;
        this.showName = function(){
            console.log(this.name);
        }
    }
    // 设置父构造函数的原型
    SuperClass.prototype.friends = ['小名', '小强'];
    SuperClass.prototype.showAge = function(){
        console.log(this.age);
    }
    // 创建子构造函数
    function SubClass(){
    
    }
    // 实现继承
    SubClass.prototype = new SuperClass();
    // 修改子构造函数的原型的构造器属性
    SubClass.prototype.constructor = SubClass;
    
    var child = new SubClass();
    console.log(child.name); // liyajie
    console.log(child.age);// 25
    child.showName();// liyajie
    child.showAge();// 25
    console.log(child.friends); // ['小名','小强']
    
    // 当我们改变friends的时候, 父构造函数的原型对象的也会变化
    child.friends.push('小王八');
    console.log(child.friends);["小名", "小强", "小王八"]
    var father = new SuperClass();
    console.log(father.friends);["小名", "小强", "小王八"]
    
    
    问题:不能给父构造函数传参 父子构造函数的原型对象之间有共享问题
    
    

2.借用构造函数

使用call和apply借用其他构造函数的成员, 可以解决给父构造函数传递参数的问题, 但是获取不到父构造函数原型上的成员.也不存在共享问题

// 创建父构造函数
function Person(name){
  this.name = name;
  this.freinds = ['小王', '小强'];
  this.showName = function(){
     console.log(this.name);
  }
}

// 创建子构造函数
 function Student(name){
  // 使用call借用Person的构造函数
  Person.call(this, name);
 }

 // 测试是否有了 Person 的成员
 var stu = new Student('Li');
 stu.showName(); // Li
 console.log(stu.friends); // ['小王','小强']

3.组合继承

借用构造函数 + 原型式继承
// 创建父构造函数
function Person(name,age){
    this.name = name;
    this.age = age;
    this.showName = function(){
        console.log(this.name);
    }
}
// 设置父构造函数的原型对象
Person.prototype.showAge = function(){
    console.log(this.age);
}
// 创建子构造函数
function Student(name){
    Person.call(this,name);
}
// 设置继承
Student.prototype = Person.prototype;
Student.prototype.constructor = Student;

上面代码解决了 父构造函数的属性继承到了子构造函数的实例对象上了,
并且继承了父构造函数原型对象上的成员
解决了给父构造函数传递参数问题

4.寄生组合继承

这种继承方式对组合继承进行了优化,组合继承缺点在于继承父类函数时调用了构造函数,我们只需要优化掉这点就行了。

function Parent(value) {
  this.val = value
}
Parent.prototype.getValue = function() {
  console.log(this.val)
}

function Child(value) {
  Parent.call(this, value)
}
Child.prototype = Object.create(Parent.prototype, {
  constructor: {
    value: Child,
    enumerable: false,
    writable: true,
    configurable: true
  }
})

const child = new Child(1)

child.getValue() // 1
child instanceof Parent // true

以上继承实现的核心就是将父类的原型赋值给了子类,并且将构造函数设置为子类,这样既解决了无用的父类属性问题,还能正确的找到子类的构造函数。

5.Class 继承

以上两种继承方式都是通过原型去解决的,在 ES6 中,我们可以使用 class 去实现继承,并且实现起来很简单

class Parent {
  constructor(value) {
    this.val = value
  }
  getValue() {
    console.log(this.val)
  }
}
class Child extends Parent {
  constructor(value) {
    super(value)
    this.val = value
  }
}
let child = new Child(1)
child.getValue() // 1
child instanceof Parent // true

class 实现继承的核心在于使用 extends 表明继承自哪个父类,并且在子类构造函数中必须调用 super,因为这段代码可以看成 Parent.call(this, value)

当然了,之前也说了在 JS 中并不存在类,class 的本质就是函数。

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