Bootstrap

ES6 面向对象

编程思想:面向过程、面向对象

面向过程:

  • 优点:逻辑清晰
  • 缺点:自行编写,率用率低
  • C语言属于面向过程编程

面向对象:

  • 特性:封装、继承、多态(实例有多种状态)
  • 优点:利用率更高;
  • 缺点:逻辑清晰度较低
  • JavaScript属于面向对象编程。

类定义

class Human{
    static num=2;    
    constructor(name,...){
        this.name=name;
    }
    static sleep(){...}
    eat(foodName){...}
}

constructor

  • 构造函数、构造器:接收实例化时的参数,初始化实例
  • 有且只有一个,未声明自动创建
  • 调用时机:new 创建实例时

类涉及关键字

this

  • 指代实例

static

  • 修饰属性和行为函数,仅类本身可用,只能通过类名调用

super

  • 既可以当函数使用,也可以当对象使用
    • 作为函数: 代表父类的构造函数,只能用在子类的构造函数中,继承全部方法;
    • 作为对象:
      • 在普通方法之中:指向父类的原型对象
      • 在普通方法中调用父类方法,super内部的this指向子类的实例
      • 当通过super为子类属性赋值时,super就是this
      • 在静态方法之中1.指向父类,2.指向子类。

当需要引用super时,需要清楚在此处super是函数还是对象,直接打印console.log(super)时会报错,因为没有指定super是什么

  1. super作为函数:只能用在子类的构造函数constructor中调用,代表父类构造函数。但它内部的this指向的是当前子类的构造函数

  2. class A{
      constructor() {    console.log(new.target.name)  }
    }
    class B extends A{    
        constructor() {
          super();//其内部的this指向的是子类B的构造函数    
        }
    }
    new A()//A
    new B()//B
    
  3. super作为对象:用在子类中,需区分是用在普通方法还是静态方法中。

普通方法中

// 一    =====》
class C{   constructor() {     }
}
C.cc=7;   C.prototype.cc=100;
class D extends C{
    constructor() {      
        super();
        // super用在普通方法中,指向父类原型,即 C.prototype
        console.log(super.cc + " and I am in D")    //100   
    }
}

// 二   =====》
class C{     
    constructor() {  this.x=11;    }
    fun(){   this.x=3;   }
    print(){   console.log(this.x)   }
}
class D extends C{      
    constructor() {
 //在constructor() 中有super继承时,方法将自动全部继承,直接调用
        super();     
        this.x=90;     }
    f(){
        super.fun();
        this.x=5;
 // 通过super调用父类方法时,super内部的this指向子类的实例
        super.print();//5  
如果此处没有this.x=5 则返回3,如果没有3,返回90,没有90,返回11
    }
}


// 三   =====》

class C{
    constructor() {}
}
// 3.当通过super为子类属性赋值时,super就是this
class D extends C{
    constructor() {super();   }
    e(){
        super.e=20;//这里的super是this
        console.log(super.e)//这里的super指向的是父类的原型对象 undefined
        console.log(this.e)//20
    }
}

静态方法中

构造函数中的值,不能被静态方法访问,因为构造函数是类的实例

// 一   =====》静态父类,指向父类(不是父类的原型对象)
class E{
    constructor() {}
    static fun(){
        console.log("我是父类的fun")}
    fun(){
        console.log("我是父类原型对象的fun")}
}
class F extends E{
    constructor() { super(); }
    //静态方法中指向的是父类的fun  即静态fun
    static son(){
        super.fun();
    }
    // 普通方法中指向的是父类的原型对象  即普通fun
    son(){
        super.fun();
    }
}
let ff=new F()
F.son()//我是父类的fun
ff.son()//我是父类原型对象的fun

// 二     =====>
// 在子类的静态方法中通过super调用父类方法时,super内部的this指向子类(不是子类的实例)
class E{
    constructor() {  this.x=2;  }
    static  print() {  console.log(this.x)  }
}
class F extends E{
    constructor() {
        super();
        this.x=4;
    }
    static p(){
        this.x=8;  
        super.print();
    }
}
let ff=new F()
F.x=11
F.p()  //8    
/*  static p()在调用时执行  this.x=8;本质比F.x=11后执行
如果没有this.x=8,则F.p()的执行会是11
如果F.x=11也没有,则输出undefined,不会输出构造函数中的2,
因为构造函数是类的实例
    */

extends 继承

  • 继承:

    • 程序中:
      • 从已有的类派生出新的类,新的类吸收已有类的属性和行为,并在其基础上,扩展新的能力(属性和行为);
      • 比如:已有类动物类,派生出鸟类、狗类、鱼类等。
      • 其中动物类为已有类(被称为父类、基类、超类),鸟类、狗类、鱼类为派生类(被称为子类、派生类)。
      • 先有子类,再有父类;
  • class:属于es6,但是是从es5演变而来,实际上就是构造函数贺原型的语法糖。

  • 关键字extends

    class 子类名称 extends 父类名称{    constructor(形参列表){        //父类构造函数调用        super(实参列表);        //定义子类独有的属性        this.属性名称=值;        .....    }    //定义子类独有行为函数    函数名称(形参列表){        函数内容    }}
    
    class Animal{    constructor(name,age,color){//'画眉',1,'黑色'        console.log('animal');        this.name=name;        this.age=age;        this.color=color;    }    eat(foodName){        console.log(`${this.name}正在吃${foodName}~`);    }    sleep(){        console.log(`${this.name}正在睡觉~`);    }}//鸟类class Bird extends Animal{    constructor(name,age,color,wing){//'画眉',1,'黑色',2        console.log('bird');        //调用父类构造函数        super(name,age,color);        this.wing=wing;    }    fly(){        console.log(`${this.name}正在飞~`);    }}let bird1=new Bird('画眉',1,'黑色',2);
    

super

  • super:用于指代父类。

  • 在构造函数中:

    • 使用super(实参列表)调用父类构造函数,调用父类构造函数必须放在子类独有属性定义前完成;
      class Animal{    
          constructor(name,age,color){        
              this.name=name;        
              this.age=age;        
              this.color=color;    
          }
      }
    class Bird extends Animal{    
        constructor(name,age,color,wing){        
            //调用父类构造函数        
            super(name,age,color);        
            this.wing=wing;    
        }
    }
    

父子间属性和函数的调用优先级

  • 当父子间存在同名属性和函数时,通过子类对象调用属性和函数,优先使用子类的属性和函数;

    class SuperClass{    
        constructor(){   this.name='父类';    }    
        demo(){     
            console.log('父类函数');   
        }
    }
    class SonClass extends SuperClass{    
        constructor(){        super();        this.name='子类';    }   
        demo(){    console.log('子类函数');    }
    }
    let son1=new SonClass();
    console.log(son1.name);
    son1.demo();
    
;