JS继承(ES5的6种继承 and ES6新增)

ES5 有 6 种方式可以实现继承,分别为

1.原型链继承

父类的实例作为子类的原型

原型链继承的基本思想是:

利用原型让一个引用类型继承另一个引用类型的属性和方法。

 //原型链继承
    function Fu() {
    
    
      this.name = "张三";
      this.age = 2;
    }
    Fu.prototype.child = function() {
    
    
      return this.name;
    };
    let a = new Fu();
    console.log(a.child());//张三

优点:

  • 简单易于实现,父类的新增的实例与属性子类都能访问

缺点:

  • 可以在子类中增加实例属性,如果要新增加原型属性和方法需要在new 父类构造函数的后面
  • 无法实现多继承
  • 创建子类实例时,不能向父类构造函数中传参数

2、借用构造函数继承(伪造对象、经典继承)

复制父类的实例属性给子类

借用构造函数的技术,基本思想为:

在子类型的构造函数中调用超类型构造函数。

//构造函数继承
    function Fu(name){
    
    
      this.name = name;
    }
    
    function Student(name){
    
    
      Fu.call(this,name);
    }
    
    let a = new Student("海绵宝宝");
    console.log(a.name);//海绵宝宝

优点:

  • 可以向超类型的构造函数传递参数
  • 解决了原型中包含 引用类型值被所有实例共享的问题

缺点:

  • 方法都在构造函数中定义,无法复用
  • 不能继承原型属性/方法,只能继承父类的实例属性和方法

3.实例继承(原型式继承)

原型继承的基本思想是:

借用原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。

// 原型式继承
    var person = {
    
    
      name:"大头儿子",
      age:2
    }
    var person1 = Object.create(person);
    person1.name = "小头爸爸";
    person1.age = 26;
    var person2 = Object.create(person);
    person2.name = "围裙妈妈";
    person2.age = 23;
    console.log(person1);// {name: "小头爸爸", age: 26}
    console.log(person2);// {name: "围裙妈妈", age: 23}

优点:

  • 不限制调用方法,简单,易实现

缺点:

  • 不能多次继承

4.组合继承(原型链 + 借用构造函数)

( 组合继承指的是将原型链和借用构造函数技术组合到一块,从而发挥二者之长的一种继承模式。)

调用父类构造函数,继承父类的属性,通过将父类实例作为子类原型,实现函数复用

基本思路:

使用原型链实现对原型属性和方法的继承,通过借用构造函数来实现对每个实例属性的继承,既通过了在原型上定义方法来实现了函数复用,有保证了每个实例都有自己的属性。

//组合继承(原型链和借用构造函数)
    function Fu(name){
    
    
      this.name = name;
    }
    Fu.prototype.sayHi = function (){
    
    
      console.log(this.name)
    }
    function Student(name){
    
    
      Fu.call(this,name)
    }
    let a = new Student("派大星");
    console.log(a.name);//派大星

5、寄生式继承

( 寄生式继承是与原型式继承紧密相关的一种思路。 )

寄生式继承的思路与寄生构造函数和工厂模式类似:

即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真的是它做了搜有的工作一样返回对象。

// 寄生式继承
    function createAnother(original){
    
    
      var clone = Object(original);
      clone.sayHi = function (){
    
    
        console.log("hi");
      };
      return clone;
    }
    var person = {
    
    
      name:'张三',
      age:2
    }
    var person2 = createAnother(person);
    person2.sayHi();//hi

缺点:

  • 使用寄生继承来为对象添加函数,会由于不能做到函数复用而效率低下。
  • 同原型链实现继承一样,包含引用类型值的属性会被所有实例共享

6.寄生组合继承

通过寄生的方式来修复组合是继承的不足,完美的实现继承

所谓寄生组合式继承,即通过构造函数来继承属性,通过原型链的混成形式来继承方法。

基本思路:

不必为了指定子类型的原理而调用超类型的构造函数,我们需要的仅仅是超类型原型的一个副本,本质上就是使用寄生式继承来继承超类型的原型,然后,再将结果指定给子类型的原型。

// 寄生组合式继承(构造函数和原型的结合)最理想的继承方案
    function inheritPrototype(subType,superType){
    
    
      var prototype = Object(superType.prototype);//创建对象
      prototype.constructor = subType;//增强对象
      subType.prototype = prototype;//指定对象
    }
    function SuperType(name){
    
    
      this.name = name;
    }
    SuperType.prototype.sayHi = function (){
    
    
      console.log(this.name);
    }
    function SuberType(name){
    
    
      SuperType.call(this,name);
    }
    inheritPrototype(SuberType,SuperType);
    var a = new SuperType("张三");
    a.sayHi();//张三

优点:

  • 只调用了一次超类构造函数,效率更高

ES6还新增一种继承方式

//class 相当于es5中构造函数
//class中定义方法时,前后不能加function,全部定义在class的protopyte属性中
//class中定义的所有方法是不可枚举的
//class中只能定义方法,不能定义对象,变量等
//class和方法内默认都是严格模式
//es5中constructor为隐式属性
class People{
    
    
  constructor(name='wang',age='27'){
    
    
    this.name = name;
    this.age = age;
  }
  eat(){
    
    
    console.log(`${
      
      this.name} ${
      
      this.age} eat food`)
  }
}
//继承父类
class Woman extends People{
    
     
   constructor(name = 'ren',age = '27'){
    
     
     //继承父类属性
     super(name, age); 
   } 
    eat(){
    
     
     //继承父类方法
      super.eat() 
    } 
} 
let wonmanObj=new Woman('xiaoxiami'); 
wonmanObj.eat();

优点:

  • 代码量少,易懂

ES5继承和ES6继承的区别:

es5继承首先是在子类中创建自己的this指向,最后将方法添加到this
Child.prototype=new Parent() || Parent.apply(this) || Parent.call(this)
es6继承是使用关键字先创建父类的实例对象this,最后在子类class中修改this

猜你喜欢

转载自blog.csdn.net/zzDAYTOY/article/details/108369003
今日推荐