类
什么是类
类由属性和方法构成,其中属性表示类的状态,而方法表示类的行为。在类的实例化过程中,会通过构造函数来初始化这些属性。可以通过Class关键字来声明一个类,其也只是个语法糖,本质还是利用原型和原型链的继承来实现。
注:函数声明和类声明之间的一个重要区别在于,函数声明会提升,类声明不会。
类的构造函数
类自身具有构造函数,其用来初始化对象的状态;类只能通过new关键字调用的。
调用构造函数内部实现过程:
- 创建一个新对象,该对象是个空对象。
obj = {} - 该对象的
__proto__指向类的原型,如Percon类obj.__proto__ = Person.prototype - 将该对象赋值给
this - 类构造函数指向代码体
- 如果类的构造函数没有返回复杂数据类型则返回
this,否则返回复杂数据类型
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
const p1 = new Person("p1", 15);
console.log(p1); //{name:'p1',age:15}
关于类的三种方法
类的实例方法
类的实例方法可以通过实例化对象来调用,相当于放到原始构造函数的prototype中
class Person {
constructor(name, age) {
this.name = name;
this._age = age;
}
// 实例方法
eating() {
console.log(this.name + "吃饭");
}
const p1 = new Person("p", 18);
// 调用实例方法
p1.eating(); //p吃饭
类的访问器属性
类的访问器属性方法同样可以通过实例化对象来调用,也相当于放到原始构造函数的prototype中
class Person {
constructor(name, age) {
this.name = name;
this._age = age;
}
// 访问器属性 访问器属性允许你在访问属性时执行自定义的读取和写入操作
get age() {
console.log("获取age");
return this._age;
}
set age(val) {
this._age = val;
}
const p1 = new Person("p", 18);
// 访问类访问器
console.log(p1.age); // 获取age 18
类的静态方法
类的静态方法只能通过类来调用,相当于放到原始构造函数的方法中,如:fn.method()
let names = ["p1", "p2", "p3"];
class Person {
constructor(name, age) {
this.name = name;
this._age = age;
}
// 3.类方法 只能通过类直接调用,不能通过实例方法调用
static randomPerson() {
let nameIndex = Math.floor(Math.random() * names.length);
let name = names[nameIndex];
let age = Math.floor(Math.random() * 99);
return new Person(name, age);
}
}
const p1 = new Person("p", 18);
// 调用类的静态方法
console.log(Person.randomPerson());
类的继承
基类:父类,派生类:子类
派生类的构造函数
派生类的构造函数和基类的构造函数不同,派生构造函数没有初始的this绑定,而是调用super()方式在构造函数创建一个this绑定,和以下代码的效果类似,其中Person是基类
this = new Person()
super关键字
- 不论基类有没有写构造函数,在派生类的构造函数中
super()必须在使用this或return之前调用。原因就是派生类的构造函数不同。- 基类的静态方法必须也在派生类的静态方法中通过super调用
super关键字可以调用父类的构造方法、实例方法、静态方法
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
eating() {
console.log(this.name + "吃饭");
}
static personMethod() {
console.log("逻辑一");
console.log("逻辑二");
console.log("逻辑三");
}
}
class Student extends Person {
constructor(name, age, sno) {
// 1.super调用父类构造函数
super(name, age);
this.sno = sno;
}
studentEating() {
console.log("学生");
// 2.super调用父类的实例方法
super.eating();
}
static sonMethod() {
// 3.super调用父类的静态方法,必须也在静态方法里才能调用父类的静态方法
console.log("学生");
super.personMethod();
}
}
const stu1 = new Student("stu1", 18, "10231");
stu1.eating(); // 学生 stu1吃饭
Student.sonMethod(); // 学生 逻辑一 逻辑二 逻辑三
方法重写
派生类可以重写基类的方法,也就是子类和父类方法名相同,通过子类创建的实例对象调用方法时会调用子类自身的方法,不会调用父类的方法。
class Person {
constructor(name) {
this.name = name;
}
eating() {
console.log("人吃饭");
}
static running(){
console.log("人跑步");
}
}
class Student extends Person {
constructor(name, sno) {
super(name);
this.sno = sno;
}
eating(){
console.log("学生吃饭");
}
static running(){
console.log("学生跑步");
}
}
const stu = new Student();
stu.eating() //学生吃饭
Student.running() //学生跑步