透析es6class里的extends及底层和super

574 阅读6分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第21天,点击查看活动详情
抛出问题: 现在统计一个学校里每个班级学生的信息,会有很多不同类型班级的学生,比如艺术班和普通班。 普通班的一个class对象:

class NormalCass{
constructor(numberPeople,className,bookName){
//班级人数
 this.numberPeople:numberPeople, 
//班级名
 this.className:className,
 //书本名
 this.bookName:bookName
}
//NormalCass原型对象中的方法
//口号的一个方法
say(){...}
//文化课一个方法
culturalLessons(){...}
}
var normalCass1=new normalCass(40,'普通班1班','数学');   
normalCass1.say();  
normalCass1.culturalLessons();

numberPeople:40,className:'普通班1班',bookName:'数学'是通过_ _proto_ _继承的class的NormalCass对象。
艺术班的一个class对象:

class ArtCass{
  constructor(numberPeople,className,instrumentName){
   //班级人数
   this.numberPeople:numberPeople, 
   //班级名
   this.className:className,
   //乐器名
   this.instrumentName:instrumentName
 }
 //ArtCass原型对象中的方法  
 //口号的一个方法
 say(){...}
 //艺术课的一个方法
 ArtLessons(){...}
}
var artCass1=new ArtCass(45,'艺术班1班','吉他');   
artCass1.say();  
artCass1.ArtLessons();

numberPeople:40,className:'普通班1班',instrumentName:'吉他'是通过_ _proto_ _继承的class的ArtCass对象。

问题:几种class包含相同的属性结构和方法定义。
解决:几种class类型间继承

几种class类型间继承

如何继承与extends和super的透析

2步:

  1. 额外创建一个父级class 父级class的构造函数中包含子类型的class中相同部分的属性结构定义,父级calss的原型对象中包含子类型class中相同部分的方法定义,既然父级class中保存了相同属性结构和方法定义,则子类class中,就可以删除所有重复的属性结构和方法定义。
    一句大白话总结:就是把多个class类型的子对象里面有相同的属性和方法,抽离出来到父级的class对象中。
class students{
 constructor(numberPeople,className){
    //班级人数
   this.numberPeople:numberPeople, 
   //班级名
   this.className:className,
 }
 //父类型Cass的原型对象 
 say(){...}
}

问题:子类型class的子对象缺少必要的属性,而且有些共有方法也无法使用了。

  1. 让子类型class继承父类型的class
    设置子类型的原型对象继承父类型的原型对象,class子类型extends父类型{...}
    原理:只是设置子类型的原型对象继承父类型的原型对象,只能保证孙子对象可以使用爷爷类型原型对象共有的方法,暂时无法为孙子对象补全缺少的属性。
class students{
 constructor(numberPeople,className){
    //班级人数
   this.numberPeople:numberPeople, 
   //班级名
   this.className:className,
 }
 //父类型Cass的原型对象 
 say(){...}
}  
//文化班
class NormalCass extends Students{
constructor(numberPeople,className,bookName){
 //书本名
 this.bookName:bookName
}
//NormalCass原型对象中的方法
culturalLessons(){...}
}
var normalCass1=new normalCass(40,'普通班1班','数学');   
normalCass1.say();  //来自爷爷,可用 
normalCass1.culturalLessons(); //来自爸爸,也可用 

//艺术班
class ArtCass extends Students{
  constructor(numberPeople,className,instrumentName){
   //乐器名
   this.instrumentName:instrumentName
 }
 //ArtCass原型对象中的方法 
 ArtLessons(){...}
}
var artCass1=new ArtCass(45,'艺术班1班','吉他');   
artCass1.say();   //来自爷爷,可用
artCass1.ArtLessons();//来自爸爸,也可用

上面我们抽离出一个父类型的class,Students,里面保存了多个子类型的class,normalCass,ArtCass共有的方法和属性。其中方法在父类型Class的原型对象中保存着,属性则在父类型Class的构造函数中保存着,子类型class继承父类型class时,使用extends,可以调用的class父类型的原型对象,这样,子类型class自己以及自己的子对象,就可以使用父class,Students的原型对象中的方法
extends底层相当于Object.setPrototypeOf(子类型的class的原型对象,父类型的原型对象)
问题:孙子对象依然缺少numberPeopleclassName属性?
解决:调用爷爷类型的构造函数,使用super关键字,super是专门指向父类型的关键字,调用super(),等于调用爷爷类型的构造函数,调用爷爷类型的构造函数,等效于执行爷爷类型的构造函数中共有的'this.xxx=xxx'语句,可为孙子对象弥补缺少的共有的属性结构。
代码如下:

class students{
 constructor(numberPeople,className){
    //班级人数
   this.numberPeople:numberPeople, 
   //班级名
   this.className:className,
 }
 //父类型Cass的原型对象 
 say(){...}
}  
//文化班
class NormalCass extends Students{
constructor(numberPeople,className,bookName){
//继承父class类型的构造函数
super(numberPeople,className);
 //书本名
 this.bookName:bookName
}
//NormalCass原型对象中的方法
culturalLessons(){...}
}
var normalCass1=new normalCass(40,'普通班1班','数学');    
//numberPeople:40,      来自奶奶
//className:'普通班1班',    来自奶奶
//bookName:'数学'    来自妈妈
normalCass1.say();  //来自爷爷,可用 
normalCass1.culturalLessons(); //来自爸爸,也可用 

//艺术班
class ArtCass extends Students{
  constructor(numberPeople,className,instrumentName){
  //继承父class类型的构造函数
   super(numberPeople,className);
   //乐器名
   this.instrumentName:instrumentName
 }
 //ArtCass原型对象中的方法 
 ArtLessons(){...}
}
var artCass1=new ArtCass(45,'艺术班1班','吉他');      
//numberPeople:40,      来自奶奶
//className:'普通班1班',    来自奶奶
//instrumentName:'吉他'    来自妈妈
artCass1.say();   //来自爷爷,可用
artCass1.ArtLessons();//来自爸爸,也可用

最后,normalCass1中的numberPeople:40,className:'普通班1班',bookName:'数学'是通过_ _proto_ _继承的父类,其中numberPeopleclassName来自奶奶,instrumentName来自妈妈。
结果:

  • 孙子对象可使用3处保存方法:自己的,父级class的,爷爷class的
  • 孙子对象中拥有两处规定的属性:父类构造函数+爷爷类构造函数

为什么叫extends?

问题:inherit是继承的意思,但是为什么用extends表示继承?
因为:继承是为了更好的扩展。
程序中的继承,都是为了在继承现有成员的基础上,进一步扩展出自己个性化的新成员。
所以,程序中的继承,都要用extends(扩展)

为什么叫super?

问题:为什么指向父类型构造函数的关键字,叫super?
因为:super在数学中指超集
所有的普通班是一个集合,所有艺术班也是一个集合,但是我们还可以用更大的集合“学生”,来包含普通班集合和艺术班集合。
这个可以包含普通班和艺术班的更大集合“学生”,就成为超集,英文名为:super。

总结

  • extends底层和Object.setPrototypeOf(子类型的class的原型对象,父类型的原型对象)类似。
  • extends只能继承父,爷爷的原型(方法),不能继承父类构造函数里的属性,这时候就用super来继承父类爷爷构造函数里的属性。
  • 有了super和extends的配合,就会让子对象有完整的属性和方法了。因此父类,爷爷构造函数内的值子对象都有。
  • extends(扩展)继承,只除了继承还有拓展,所以用这个字段名。super,超大集合的意思(超级)