网站
引入
在 class 出现之前,JavaScript 创建可复用的对象要用构造函数加原型链,写起来比较绕。
class 提供了一种更清晰、更接近其他语言的方式来定义对象模板和处理继承。它本质上是构造函数和原型链的语法糖。
正文
定义
class是 ES6 新增的语法,用来定义一个对象模板(类),可以通过new关键字创建该类的实例。
基本语法
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(`你好,我是${this.name},今年${this.age}岁`);
}
}
const person = new Person("Tom", 18);
person.sayHello();constructor() 是构造方法,new 的时候自动执行,用来初始化实例的属性。
实例属性和方法
在 class 内部定义的方法,所有实例共享。
class Animal {
constructor(name, sound) {
this.name = name;
this.sound = sound;
}
speak() {
console.log(`${this.name}说:${this.sound}`);
}
}
const cat = new Animal("猫", "喵");
const dog = new Animal("狗", "汪");
cat.speak();
dog.speak();类字段可以直接在类体内声明(不需要写在 constructor 里):
class Counter {
count = 0;
increment() {
this.count = this.count + 1;
}
}
const counter = new Counter();
counter.increment();
counter.increment();
console.log(counter.count);静态方法
用 static 声明的方法属于类本身,不属于实例。
class MathUtils {
static add(a, b) {
return a + b;
}
static subtract(a, b) {
return a - b;
}
}
console.log(MathUtils.add(3, 5));
console.log(MathUtils.subtract(10, 4));静态方法不能通过实例调用,只能通过类名调用。
const utils = new MathUtils();
console.log(utils.add(1, 2));Getter 和 Setter
用 get 和 set 可以像访问属性一样调用方法。
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
get fullName() {
return `${this.firstName}${this.lastName}`;
}
set fullName(value) {
const parts = value.split(" ");
this.firstName = parts[0];
this.lastName = parts[1];
}
}
const person = new Person("张", "三");
console.log(person.fullName);
person.fullName = "李 四";
console.log(person.firstName);
console.log(person.lastName);继承
用 extends 让一个类继承另一个类。
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name}发出了声音`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
speak() {
console.log(`${this.name}汪汪叫`);
}
}
const dog = new Dog("旺财", "金毛");
dog.speak();
console.log(dog.breed);super() 调用父类的 constructor(),必须在子类的 constructor 里先调用 super(),才能使用 this。
用 super 也可以调用父类的方法:
class Dog extends Animal {
speak() {
super.speak();
console.log("而且它是一只狗");
}
}对比构造函数写法
传统构造函数写法:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHello = function () {
console.log(`你好,我是${this.name}`);
};class 写法:
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(`你好,我是${this.name}`);
}
}两者效果一样,class 写法更直观,继承也更清晰。
常见写法
| 写法 | 说明 |
|---|---|
class Name {} | 声明一个类 |
constructor() | 构造方法,new 时自动执行 |
methodName() | 实例方法 |
static methodName() | 静态方法,通过类名调用 |
get name() | Getter,像属性一样访问 |
set name(val) | Setter,像赋值一样调用 |
class A extends B | 继承 |
super() | 调用父类构造方法 |
例子
简单的用户类
class User {
constructor(name, email) {
this.name = name;
this.email = email;
this.createdAt = new Date();
}
getInfo() {
return `${this.name} (${this.email})`;
}
}
class Admin extends User {
constructor(name, email, role) {
super(name, email);
this.role = role;
}
getInfo() {
return `${super.getInfo()} - ${this.role}`;
}
}
const user = new User("Tom", "[email protected]");
const admin = new Admin("Jack", "[email protected]", "管理员");
console.log(user.getInfo());
console.log(admin.getInfo());理解
可以把 class 理解为对象的蓝图。
就像盖房子之前要先画图纸一样,class 就是这张图纸。图纸上写了房子有哪些房间(属性)、能做什么事情(方法)。
用 new 就是按照图纸盖出一栋真实的房子(实例)。
继承就像在基础图纸上做修改,新图纸保留了原来的结构,又加了新的功能。
class 不是什么新的底层机制,它只是让构造函数和原型链的写法更好看、更容易理解。
引出
class 底层依赖的是 JS 原型和原型链,理解原型链能帮你搞清楚继承的原理。
class 也可以看作一种 JS 自定义对象 的方式,和之前用构造函数创建对象的写法对比着学效果更好。