编程思想:面向过程、面向对象
面向过程:
- 优点:逻辑清晰
- 缺点:自行编写,率用率低
- 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是什么
-
super作为函数:只能用在子类的构造函数constructor中调用,代表父类构造函数。但它内部的this指向的是当前子类的构造函数
-
class A{ constructor() { console.log(new.target.name) } } class B extends A{ constructor() { super();//其内部的this指向的是子类B的构造函数 } } new A()//A new B()//B
-
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();