继承

70 阅读1分钟

这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战

继承

继承,是一个很熟悉的词汇。在现实生活中,两个有血缘关系的人,如果年长的人离开人世间了,那么年轻的就可以获得年长者留下来的所有财产。年轻人得到年长者财产的这一过程就是继承。javaScript中,一个类获得另外一个类的所有属性、方法,这也是继承。

  • 先给个父类构造函数
function Animal(name) {
    this.name = name;
    this.run = () => {
        console.log(`${this.name}正在努力的奔跑着`)
    }
}

原型链继承

  • 原型链继承简单来说就是一个引用类型继承给另一个引用类型,使得自己拥有被继承者的属性和方法。
Animal.prototype.age = 2
function Dog() {}
Dog.prototype = new Animal('阿黄')
let bigYellowDog = new Dog()
bigYellowDog.run() // 阿黄正在努力的奔跑着
bigYellowDog.age // 2
  • 每个构造函数都有一个原型对象,原型对象中有个constructor指针指向构造函数,而实例对象也有个__proto__指向构造函数的原型对象。那么,我们可以new一个Animal的实例出来并赋值给Dog的原型对象,此时的Dog的原型对象包含着Animal的实例对象,这个实例对象又指向着Animal的原型对象,Animal的原型对象又指向着Animal函数,所以Dog函数拥有Animal的属性和方法。Dog的实例bigYellowDog也拥有Animal的name属性和run方法。
  • 原型链继承有个不太好的地方就是创建实例时无法向父类构造函数传递参数;来自原型对象的所有属性被所有实例共享(当你改变一个实例的原型对象的属性或者方法,其他实例的原型对象的属性和方法都会跟着改变)

借用构造函数

  • 借用构造函数实质上就是父类构造函数传进来,利用call()或者apply()将子类构造函数this指向父类构造函数,从而得到父类构造函数的属性和方法。
Animal.prototype.age = 3
function Dog(name){
    Animal.call(this, name);
    this.age = 2;
}
let smallYellow = new Dog('小黄')
smallYellow.run() //小黄正在努力的奔跑着
console.log(smallYellow.age) // 2

  • 如上所示,可以把名字“小黄”传进去,并且在打印smallYellow的age属性时,获取到的是构造函数Dog的属性;借用函数继承解决了原型链继承不能传参和来自原型对象的所有属性被所有实例共享两个问题。不过也是有缺点的,只能继承父类函数的属性,不能继承父类原型对象上的属性;不能实现函数复用,每个实例都有父类函数的副本。

组合继承

  • 组合继承,就是将原型链继承和借用构造函数继承两者结合起来用,保留他们各自的优点,可以传递参数和复用属性和方法。
Animal.prototype.age = 3
function Dog(name){
    Animal.call(this, name) ;
    this.age = 2;
}
Dog.prototype = new Animal()
let smallYellow = new Dog('小黄')
smallYellow.run() //小黄正在努力的奔跑着
console.log(smallYellow.age) // 2
  • 如上所示,子类实例可以调用父类函数的run方法,也拥有父类函数的原型对象的属性age。

寄生式继承

  • 寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,该 函数在内部以某种方式来增强对象,最后再像真地是它做了所有工作一样返回对象。
function createPerson(obj) {
    let clonePerson = Object.create(obj)
    clonePerson.sayHi = () => {
        console.log('你好,未知的朋友')
    }
    return clonePerson
}
let people = {
    name: '小强'
}
let student = createPerson(people)
console.log(student.name)
  • 如上所示,在createPerson函数中创建一个新的对象clonePerson,给这个clonePerson赋予新的技能sayHi(), 再将clonePerson return出去,student来接收这个新对象。这时的student就拥有clonePerson的属性和方法、people的属性和方法。

寄生组合式继承

  • 上面介绍的组合继承有个问题,每次使用时都会调用两次;寄生组合式继承则可以解决这个问题,因为它是通过借用构造函数来继承属性以及通过原型链来继承方法。
function SuperType(name) {
  this.name = name;
}
SuperType.prototype.sayHi = function(){
  return this.name;
}
function SubType(name) {
  this.name = '';
  SuperType.call(this, name);
}
function inheritPrototype(subtype, supertype) {
  let proto = Object.create(supertype.prototype);
  proto.constructor = subtype;
  subtype.prototype = proto;
}
SubType.prototype.run = function() {
console.log(`${this.name}正在努力的向前跑着`);
}
let dog = new SubType('阿黄');
dog.run(); // 阿黄正在努力的向前跑着