JS继承几种方式

一 原型链继承:核心: 将父类的实例作为子类的原型(父类子类都是构造函数,通过类创建对象)

  • 优点:方法复用
    方法定义在父类的原型上,可以复用父类构造函数的方法,比如say方法。
  • 缺点:
    • 创建子类实例时,无法传父类参数
    • 引用类型的值的原型会被所有实例共享
    • 继承单一,无法实现多继承(在JavaScript中继承是依赖于原型prototype链实现的,只有一条原型链,理论上是不支持继承多个父类的,可以通过变通的方式实现类似功能)
 1     function SuperType(){
 2         this.property=true;
 3     }
 4     SuperType.prototype.getSuperValue=function(){
 5         return this.property;
 6     };
 7     function SubType(){
 8         this.subproperty=false;
 9     }
10     //继承了SuperType
11     SubType.prototype=new SuperType();
12 
13     SubType.prototype.getSubValue=function(){
14         return this.subproperty;
15     };
16     var instance=new SubType();
17     console.log(instance.getSuperValue());  //true

 

 1     function SuperType(){
 2         this.colors=["red","blue"];
 3     }
 4     function SubType(){
 5     }
 6     //继承了SuperType
 7     SubType.prototype=new SuperType();
 8     var ins1=new SubType();
 9     ins1.colors.push("black")   //"red,blue,black"
10     var ins2=new SubType();
11     console.log(ins2.colors);   //"red,blue,black"

 

二 构造函数继承:核心:借用父类构造函数来增强子类实例,等于是复制父类的实例属性给子类

优点:实例之间独立

  • 创建子类实例,可以向父类构造函数传参
  • 子类实例不共享父类构造函数的引用属性,如arr
  • 可实现多继承(通过多个call或apply继承多个父类)

缺点:

  • 父类方法不能复用
  • 由于方法在父构造函数中定义,导致方法不能复用(每次创建子类实例都要创建一遍方法)
  • 子类实例继承不了父类原型上的属性,因为没有用到原型
  function Parent(name) {
    this.name = name;    //实例基本属性(该属性,强调私有,不共享)
    this.arr = [1];  // (该属性,强调私有)
    this.say = function () {    //实例引用属性(该属性,强调复用,需要共享)
      console.log('hello');
    }
  }
  function Child(name, like) {
    console.log(this);
    Parent.call(this, name);    //核心,拷贝了父类的实例属性和方法
    this.like = like;
  }
  let boy1 = new Child('小刚', 'apple');
  let boy2 = new Child('小明', 'orange');

  //优点1:可向父类构造函数传参
  console.log(boy1.name, boy2.name);    //小刚,小明
  //优点2:不共享父类构造函数的引用属性
  boy1.arr.push(2);
  console.log(boy1.arr, boy2.arr);    //[1,2],[1]

  //缺点1:方法不能复用
  console.log(boy1.say === boy2.say);    //false (说明boy1和boy2的say方法独立,不是共享的)

  //缺点2:不能继承父类原型上的方法
  Parent.prototype.walk = function () {
    console.log('我会走路');
  }
  boy1.walk;    //undefined(说明实例不能获得父类原型上的方法)

 

三 拷贝继承:

 

四 组合继承:核心:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过原型链继承将父类实例作为子类原型,实现函数复用

优点:

  1. 父类的方法定义在原型对象上,可以实现方法复用
  2. 创建子类实例,可以向父类构造函数传参;并且不共享父类的引用属性,如arr

缺点:由于调用了2次父类的构造方法,会存在一份多余的父类实例属性

 

五 原型式继承:

缺点:引用类型值会共享,值类型不会共享,因此在改变值类型时,相当于给自己添加了属性。

 function object(o){
    function F(){}
    //F.prototype={name:'ccdida',friends:['shelly','Bob']}
    F.prototype=o
    // new F() 
    //F是个构造函数,返回F的实例:1.this此时用不上 2.将实例的__proto__指向F.prototype.
    //即返回了一个实例,其__proto__指向{name:'ccdida',friends:['shelly','Bob']}
    return new F()
  }
  var person={
    name:'ccdida',
    friends:['shelly','Bob']
  }
  var person1=object(person)
  var person2=object(person)
  //object函数相当于实现了Object.Create的功能
  console.log(person1.__proto__===person) //true 
  person2.friends.push('shlimy')
  console.log(person1.friends)// ["shelly", "Bob", "shlimy"]

 

六 寄生组合继承:核心:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点 

 1  function Parent(name) {
 2     this.name = name;    //实例基本属性(该属性,强调私有,不共享)
 3     this.arr = [1];        //实例引用属性(该属性,强调私用,不共享)
 4   }
 5   Parent.prototype.say = function () {    //将需要复用、共享的方法定义在父类原型上
 6     console.log('hello');
 7   }
 8   function Child(name, like) {
 9     Parent.call(this, name);    //核心
10     this.like = like;
11   }
12   //核心 通过创建中间对象,子类原型和父类原型就会隔离开,不再是同一个,有效避免了方式4的缺点
13   Child.prototype = Object.create(Parent.prototype);
14 
15   Child.prototype.constructor = Child;//修复代码
16 
17   let boy1 = new Child('小刚', 'apple');
18   let boy2 = new Child('小明', 'orange');
19   let p1 = new Parent('小爸爸');
20 
21   console.log(boy1.constructor, p1.constructor);    //修复之后:Child,Parent
22 
23 
24   // Object.create()函数等价为:下面函数即是原型式继承实现
25   function object(o) {
26     function F() { }
27     F.prototype = o;
28     return new F();
29   }
30 
31   // 于是中间那段核心代码可改为:
32   function object(o) {
33     function F() { }
34     F.prototype = o;
35     return new F();
36   }
37   Child.prototype = object(Parent);
38 
39   Child.prototype.constructor = Child;

 

JS继承的实现方式:https://www.cnblogs.com/humin/p/4556820.html

JS五种继承方法和优缺点:https://blog.csdn.net/m0_51235736/article/details/113795449 

ES6中extends类继承实现原理 

 

 

 

 

posted @ 2021-04-08 07:59  TerryMin  阅读(169)  评论(0编辑  收藏  举报