网站

class 类 | MDN

Class 的基本语法 | 阮一峰

引入

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

getset 可以像访问属性一样调用方法。

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 自定义对象 的方式,和之前用构造函数创建对象的写法对比着学效果更好。