在 JavaScript 中,类(Class)是 ES6(ECMAScript 2015)引入的核心特性,它提供了一种更清晰、更面向对象的方式来创建对象和处理继承。
基本语法
class Person {
// 构造函数
constructor(name, age) {
this.name = name;
this.age = age;
}
// 方法
greet() {
return `你好,我是${this.name},今年${this.age}岁。`;
}
// 静态方法
static info() {
return "这是一个Person类";
}
}
// 使用类
const alice = new Person("Alice", 30);
console.log(alice.greet()); // "你好,我是Alice,今年30岁。"
console.log(Person.info()); // "这是一个Person类"
核心概念
1. 构造函数(Constructor)
-
使用
constructor
方法定义 -
在创建类的新实例时自动调用
-
用于初始化对象属性
2. 方法(Methods)
-
类中定义的函数
-
自动添加到类的原型上
-
实例可以调用这些方法
3. 静态方法(Static Methods)
-
使用
static
关键字定义 -
只能通过类本身调用,不能通过实例调用
-
常用于工具函数或与类相关的操作
4. 继承(Inheritance)
-
使用
extends
关键字实现继承 -
子类可以通过
super
调用父类的构造函数和方法
class Student extends Person {
constructor(name, age, grade) {
super(name, age); // 调用父类的constructor
this.grade = grade;
}
study() {
return `${this.name}正在学习${this.grade}年级的课程`;
}
// 重写父类方法
greet() {
return `${super.greet()} 我是一名${this.grade}年级的学生。`;
}
}
const bob = new Student("Bob", 15, 9);
console.log(bob.study()); // "Bob正在学习9年级的课程"
console.log(bob.greet()); // "你好,我是Bob,今年15岁。 我是一名9年级的学生。"
高级特性
1. Getter 和 Setter
class Rectangle {
constructor(width, height) {
this._width = width;
this._height = height;
}
// Getter
get area() {
return this._width * this._height;
}
// Setter
set width(value) {
if (value > 0) {
this._width = value;
} else {
console.log("宽度必须大于0");
}
}
get width() {
return this._width;
}
}
const rect = new Rectangle(10, 5);
console.log(rect.area); // 50 (使用getter)
rect.width = 15; // 使用setter
console.log(rect.area); // 75
2. 私有字段(ES2022+)
class BankAccount {
// 私有字段(以#开头)
#balance = 0;
constructor(initialBalance) {
this.#balance = initialBalance;
}
deposit(amount) {
if (amount > 0) {
this.#balance += amount;
return `存款成功,当前余额:${this.#balance}`;
}
return "存款金额必须大于0";
}
withdraw(amount) {
if (amount > 0 && amount <= this.#balance) {
this.#balance -= amount;
return `取款成功,当前余额:${this.#balance}`;
}
return "取款金额无效";
}
// 公共方法访问私有字段
getBalance() {
return this.#balance;
}
}
const account = new BankAccount(1000);
console.log(account.deposit(500)); // "存款成功,当前余额:1500"
console.log(account.withdraw(200)); // "取款成功,当前余额:1300"
console.log(account.getBalance()); // 1300
// console.log(account.#balance); // 错误:私有字段无法外部访问
3. 静态字段和静态块(ES2022+)
class Configuration {
// 静态公共字段
static apiUrl = "https://api.example.com";
// 静态私有字段
static #apiKey = "SECRET_KEY";
// 静态初始化块
static {
// 可以执行复杂的静态初始化逻辑
if (process.env.NODE_ENV === "development") {
this.apiUrl = "https://dev-api.example.com";
}
}
// 静态方法访问静态私有字段
static getApiKey() {
return this.#apiKey;
}
}
console.log(Configuration.apiUrl); // 根据环境不同
console.log(Configuration.getApiKey()); // "SECRET_KEY"
类与原型继承的关系
JavaScript 的类本质上是基于原型继承的语法糖:
// 类语法
class Person {
constructor(name) {
this.name = name;
}
greet() {
return `Hello, ${this.name}!`;
}
}
// 等价的原型语法
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
return `Hello, ${this.name}!`;
};
类与普通函数的区别
特性 | 类 | 普通函数 |
---|---|---|
调用方式 | 必须使用 new 关键字 | 可以普通调用 |
提升 | 不会被提升 | 会被提升 |
严格模式 | 始终在严格模式下执行 | 取决于上下文 |
原型方法 | 在类体内定义 | 手动添加到原型 |
静态方法 | 使用 static 关键字 | 直接添加到构造函数 |
私有字段 | 支持(ES2022+) | 不支持 |
最佳实践
-
使用类代替构造函数:提供更清晰的语法结构
-
优先使用类字段语法:使属性初始化更直观
-
合理使用继承:保持继承层次简单(避免深层继承)
-
利用私有字段:封装内部实现细节
-
使用静态方法:对于不依赖实例的操作
-
考虑组合代替继承:对于复杂关系,使用组合可能更灵活
// 组合示例
class Logger {
log(message) {
console.log(`[LOG]: ${message}`);
}
}
class UserService {
constructor(logger) {
this.logger = logger;
}
register(user) {
// 注册逻辑...
this.logger.log(`用户 ${user.name} 注册成功`);
}
}
const logger = new Logger();
const userService = new UserService(logger);
userService.register({ name: "Alice" });
浏览器兼容性
JavaScript 类在现代浏览器中得到广泛支持:
-
Chrome 49+(2016年3月)
-
Firefox 45+(2016年3月)
-
Safari 10+(2016年9月)
-
Edge 13+(2016年)
-
Node.js 6.0+(2016年4月)
对于旧版浏览器,可以使用 Babel 等转译工具将类语法转换为 ES5 代码。
总结
JavaScript 的类提供了:
-
更清晰、更结构化的面向对象编程方式
-
简洁的继承语法(
extends
和super
) -
封装能力(私有字段和方法)
-
静态成员支持
-
Getter/Setter 访问器
虽然类本质上是基于原型的语法糖,但它们显著提高了代码的可读性和可维护性。在现代 JavaScript 开发中,类已成为创建复杂对象和组织代码结构的标准方式。