Skip to content

继承总结

🕒 Published at:

继承是很经典的面试问题,今天我们来现在整体总结一下

ES6继承

js
class Parent {
    constructor(name){
      this.name = name
    }
  
    sayHi(){
      console.log('HI~~~')
    }
  }
  
  class Child extends Parent {
    constructor(name,type){
        super(name)
        this.type = type
    }
    sayHello(){
      console.log('hello')
    }
  }
  
  const c1 = new Child('c1','child')
  console.log(c1.name,c1.type)
  c1.sayHi()

ES5 继承

注意,在es6之前,没有class 类语法

原型链继承

js
function Person(name) {
    this.name = name || '父类';
    this.hobby = ['eat','sleep']
}

// 将需要共享的方法放在父类原型上
Person.prototype.sayHello = function(name){
   console.log(`Hello, my name is ${name}`);
}

function Child(like){
  this.like = like
}
Child.prototype = new Person() // 此时,Child.prototype.constructor = Person
Child.prototype.constructor = Child //修正constructor指向

const child = new Child('football')
child.sayHello('child') // Hello, my name is child
console.log(child.like,child.hobby) // football [ 'eat', 'sleep' ] 父类

const child1 = new Child('football')
const child2 = new Child('piano')
child1.hobby.push('code')
child1.name = 'child1'
child2.name = 'child2'
console.log(child1.name,child2.name) // child1 child2
console.log(child1.hobby,child2.hobby) //[ 'eat', 'sleep', 'code' ] [ 'eat', 'sleep', 'code' ]

优点:共享了父类构造函数的方法 缺点:1. 不能向父类构造函数传参,如name; 2. 子类实例共享父类构造函数的引用属性(arr) 注意:修改child1的name属性,是不会影响到child2.name。因为设置child1.name相当于在⼦类实例新增了name属性。

借用构造函数继承

js
function Parent(name){
    this.name = name
    this.hobby = ['football','piano']
    this.sayName = function(){
        console.log('hello' + this.name);
    }
}

function Child(name,age){
    Parent.call(this,name),
    this.age = age
}

const child1 = new Child('child1',18)
const child2 = new Child('child2',28)
child1.hobby.push('coding')

Parent.prototype.sayHello = function(){
    console.log('hello');
}

console.log(child1.hobby,child2.hobby) // [ 'football', 'piano', 'coding' ] [ 'football', 'piano' ]
console.log(child1.sayName==child2.sayName) // false 说明每个实例的sayName都是独立的
child1.sayHello() //child1.sayHello is not a function

优点:可以向父类构造函数传参; 实例之间相互独立;不共享父类构造函数的方法 缺点:方法不能复用;不能获得父类原型上的方法;

组合继承

js
function Parent(name){
    this.name = name;
    this.hobby = ['football','piano'];
}

Parent.prototype.sayHello = function(){
    console.log('hello');
}

function Child(name,age){
    Parent.call(this,name);
    this.age = age;
}
Child.prototype = new Parent()
Child.prototype.constructor = Child

const child1 = new Child('zhangsan',18)
const child2 = new Child('lisi',20)

child1.hobby.push('swimming')
console.log(child1.hobby) // [ 'football', 'piano', 'swimming' ]
console.log(child2.hobby) // [ 'football', 'piano' ]
console.log(child1.sayHello ==  child2.sayHello)  // true
child1.sayHello() // hello

优点:可以向父类构造函数传参;不共享父类构造函数中的引用类型属性;可以公用父类原型对象中的方法 缺点:调用了两次父类构造函数,会存在一份多余的父类构造函数实例

寄生组合继承(完美解决方案)

javascript
function Parent(name){
  this.name = name
  this.hobby = ['football','piano']
}
Parent.prototype.sayHello = function(){
    console.log('hello')
}

function Child(name,age){
  Parent.call(this,name)
  this.age = age
}

Child.prototype =Object.create(new Parent())
Child.prototype.constructor = Child

那么es6 的继承经过babel转换后是那种es5的继承呢? 当然是寄生组合继承,其中 Parent.call(this,name)模拟super关键字