继承

294 阅读3分钟

原型链继承

重点:让子类的原型等于父类的实例

优点:

  1. 可以访问父类的属性和方法 以及 父类原型上的属性和方法
  2. 父类新增的原型方法/原型属性,子类都能及时访问到

缺点:

  1. 新实例无法向父类构造函数传参
  2. 继承单一,无法实现多继承
  3. 子类继承父类的属性和方法是将父类的私有属性和公有方法都作为自己的公有属性和方法
  4. 所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性 也会被修改!)
function Parent(){
    this.name = 'Hello world';
}

Parent.prototype.getName = function(){
    console.log(this.name);
}

function Child(){

}

Child.prototype = new Parent();
var child1 = new Child();
child1.getName(); // Hello world

构造函数继承(call继承)

重点:用.call().apply()将父类构造函数引入子类函数(在子类 函数中做了父类函数的自执行(复制))

优点:

  1. 只继承了父类构造函数的属性,没有继承父类原型的属性。
  2. 解决了原型链继承缺点1、2、3。
  3. 可以继承多个构造函数属性(call多个)。
  4. 在子实例中可向父实例传参。

缺点:

  1. 无法访问原型链上的属性和方法, 只能继承父类构造函数的属性。
  2. 无法实现构造函数的复用。(每次用每次都要重新调用)
  3. 每个新实例都有父类构造函数的副本,臃肿。
function Parent(){
    this.name = 'xiaoming';
    this.colors = ['red', 'blue', 'green'];
}

Parent.prototype.getName = function(){
    console.log(this.name);
}

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

var child1 = new Child(23);
var child2 = new Child(12);
child1.colors.push('yellow');
console.log(child1.name); // xiaoming
console.log(child1.colors); // ["red", "blue", "green", "yellow"]
console.log(child2.colors); // ["red", "blue", "green"]

组合继承(组合原型链继承和借用构造函数继承)(常用)

重点:结合了两种模式的优点,传参和复用

优点:

  1. 可以继承父类原型上的属性,可以传参,可复用。
  2. 每个新实例引入的构造函数属性是私有的。

缺点:

  1. 调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数。
  2. 没办法辨别是实例是子类还是父类创造的,子类和父类的构造函数指向是同一个
function Parent(name){
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}

Parent.prototype.getName = function(){
    console.log(this.name);
}

function Child(name,age){
    Parent.call(this,name);// 第二次调用 Parent()
    this.age = age;
}

Child.prototype = new Parent(); // 第一次调用 Parent()

var child1 = new Child('xiaopao',18);
var child2 = new Child('lulu',19);

优化组合继承

function Parent(name){
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}

Parent.prototype.getName = function(){
    console.log(this.name);
}

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

Child.prototype = Parent.prototype;
Child.prototype.constructor = Child;

var child1 = new Child('xiaopao',18);
var child2 = new Child('lulu',19);

class继承

class Parent5 {
  constructor() {
    this.name = ['super5']
  }
  reName() {
    this.name.push('new 5')
  }
}
class Child5 extends Parent5 {
  constructor() {
    super()
  }
}
var child51 = new Child5()
var child52 = new Child5()

冒充对象继承

核心:使用父类的构造函数来增强子类实例

特点:把父类私有的和公有的克隆一份一样的给子类

function Son(){
    var temp = new Father()
    for(var k in temp){
        this[k] = temp[k]
    }
    temp = null
}

var son = new Son()
console.log(son.sleep()) // father正在睡觉
console.log(son.look('TV')) // father正在看TV

参考文章:

juejin.cn/post/684490…

segmentfault.com/a/119000001…