1. JavaScript中的Class基础概念
在ES6之前,JavaScript通过原型链(prototype)实现面向对象编程,这种方式虽然灵活但不够直观。2015年发布的ES6标准正式引入了class语法糖,让JavaScript的面向对象编程更加清晰易懂。
Class本质上仍然是基于原型继承的语法糖,但它提供了更接近传统面向对象语言的写法。一个简单的类定义如下:
javascript复制class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello, my name is ${this.name}`);
}
}
这里有几个关键点需要注意:
constructor是类的构造函数,在通过new创建实例时自动调用- 方法之间不需要逗号分隔
- 类名通常采用PascalCase命名规范
提示:虽然class看起来像其他语言中的类,但JavaScript的class本质上仍然是函数。
typeof Person会返回"function"。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Class的核心特性详解
2.1 构造函数与实例属性
构造函数constructor是类中一个特殊方法,它在创建类实例时自动调用。我们可以在构造函数中初始化实例属性:
javascript复制class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
get area() {
return this.height * this.width;
}
}
const rect = new Rectangle(10, 20);
console.log(rect.area); // 200
2.2 静态方法与属性
静态方法和属性属于类本身,而不是类的实例。它们通常用于实现与类相关的工具函数:
javascript复制class MathUtils {
static PI = 3.14159;
static circleArea(radius) {
return this.PI * radius * radius;
}
}
console.log(MathUtils.circleArea(5)); // 78.53975
2.3 Getter与Setter
Getter和Setter允许你定义访问和设置属性时的自定义行为:
javascript复制class Temperature {
constructor(celsius) {
this.celsius = celsius;
}
get fahrenheit() {
return this.celsius * 1.8 + 32;
}
set fahrenheit(value) {
this.celsius = (value - 32) / 1.8;
}
}
const temp = new Temperature(25);
console.log(temp.fahrenheit); // 77
temp.fahrenheit = 68;
console.log(temp.celsius); // 20
3. 继承与多态
3.1 基本继承
JavaScript使用extends关键字实现继承:
javascript复制class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
speak() {
console.log(`${this.name} barks.`);
}
}
const dog = new Dog('Rex');
dog.speak(); // Rex barks.
3.2 super关键字
super关键字用于调用父类的方法或构造函数:
javascript复制class Cat extends Animal {
constructor(name, color) {
super(name); // 调用父类构造函数
this.color = color;
}
speak() {
super.speak(); // 调用父类方法
console.log(`${this.name} meows.`);
}
}
3.3 方法重写与多态
子类可以重写父类的方法,实现多态行为。JavaScript会根据运行时对象的实际类型调用相应的方法:
javascript复制const animals = [
new Animal('Generic'),
new Dog('Buddy'),
new Cat('Whiskers')
];
animals.forEach(animal => animal.speak());
// Generic makes a noise.
// Buddy barks.
// Whiskers makes a noise.
// Whiskers meows.
4. Class的高级特性
4.1 私有字段与方法
ES2022正式引入了私有字段和方法的语法,使用#前缀:
javascript复制class Counter {
#count = 0; // 私有字段
#increment() { // 私有方法
this.#count++;
}
tick() {
this.#increment();
return this.#count;
}
}
const counter = new Counter();
console.log(counter.tick()); // 1
console.log(counter.#count); // 报错:私有字段无法从类外部访问
4.2 类表达式
与函数一样,类也可以使用表达式形式定义:
javascript复制const Person = class {
constructor(name) {
this.name = name;
}
};
const person = new Person('Alice');
4.3 动态类成员
类成员可以是动态计算的:
javascript复制const methodName = 'getArea';
class Circle {
constructor(radius) {
this.radius = radius;
}
[methodName]() {
return Math.PI * this.radius ** 2;
}
}
const circle = new Circle(5);
console.log(circle.getArea()); // 78.53981633974483
5. Class与原型链的关系
虽然class语法更简洁,但理解其背后的原型链机制仍然很重要:
javascript复制class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello, ${this.name}`);
}
}
// 等价的原型链写法
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`Hello, ${this.name}`);
};
关键区别:
- class声明不会被提升(hoisting)
- class中的所有代码默认在严格模式下执行
- class方法是不可枚举的
6. 常见问题与最佳实践
6.1 类与工厂函数的对比
在某些场景下,工厂函数可能是比class更好的选择:
javascript复制// 类方式
class User {
constructor(name) {
this.name = name;
}
}
// 工厂函数方式
function createUser(name) {
return {
name,
greet() {
console.log(`Hi, I'm ${this.name}`);
}
};
}
选择依据:
- 需要继承时使用class
- 需要创建多个相似对象但不需要继承时考虑工厂函数
- 需要私有成员时,class的#语法更直观
6.2 内存管理注意事项
类实例会保持对其方法的引用,这可能导致内存泄漏:
javascript复制class HeavyObject {
constructor() {
this.data = new Array(1000000).fill('data');
}
process() {
// 处理数据
}
}
let instance;
function createInstance() {
instance = new HeavyObject();
// 即使不再需要,instance仍保留在内存中
}
解决方案:
- 及时将不再需要的实例设为null
- 避免在全局作用域保存实例引用
- 考虑使用WeakMap存储私有数据
6.3 性能考量
在现代JavaScript引擎中,class的性能通常与原型链写法相当。但在某些情况下需要注意:
- 频繁创建和销毁大量小对象时,考虑对象池模式
- 避免在热代码路径中动态添加/删除方法
- 对于性能关键代码,测试不同实现方式的性能差异
7. 实际应用案例
7.1 UI组件开发
Class非常适合用于组织UI组件代码:
javascript复制class Modal {
constructor(selector) {
this.element = document.querySelector(selector);
this.isOpen = false;
}
open() {
this.element.style.display = 'block';
this.isOpen = true;
}
close() {
this.element.style.display = 'none';
this.isOpen = false;
}
toggle() {
this.isOpen ? this.close() : this.open();
}
}
const myModal = new Modal('#my-modal');
document.getElementById('open-btn').addEventListener('click', () => myModal.open());
7.2 游戏开发中的实体系统
在游戏开发中,class可以很好地表示游戏实体:
javascript复制class GameObject {
constructor(x, y) {
this.x = x;
this.y = y;
this.components = [];
}
addComponent(component) {
this.components.push(component);
component.gameObject = this;
}
update(deltaTime) {
this.components.forEach(c => c.update?.(deltaTime));
}
}
class SpriteComponent {
constructor(imageSrc) {
this.image = new Image();
this.image.src = imageSrc;
}
update() {
// 渲染逻辑
}
}
const player = new GameObject(100, 100);
player.addComponent(new SpriteComponent('player.png'));
7.3 数据模型定义
Class非常适合定义应用中的数据模型:
javascript复制class Product {
constructor(id, name, price) {
this.id = id;
this.name = name;
this.price = price;
}
applyDiscount(percent) {
this.price *= (1 - percent / 100);
return this.price;
}
static fromJSON(json) {
const data = JSON.parse(json);
return new Product(data.id, data.name, data.price);
}
}
const product = new Product(1, 'Laptop', 999);
product.applyDiscount(10); // 899.1
8. 类设计模式实践
8.1 单例模式
使用class实现单例模式:
javascript复制class Logger {
static instance;
constructor() {
if (Logger.instance) {
return Logger.instance;
}
this.logs = [];
Logger.instance = this;
}
log(message) {
this.logs.push(message);
console.log(message);
}
getLogs() {
return [...this.logs];
}
}
const logger1 = new Logger();
const logger2 = new Logger();
console.log(logger1 === logger2); // true
8.2 观察者模式
实现一个简单的事件观察者系统:
javascript复制class EventEmitter {
constructor() {
this.events = {};
}
on(event, listener) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(listener);
}
emit(event, ...args) {
if (this.events[event]) {
this.events[event].forEach(listener => listener(...args));
}
}
off(event, listenerToRemove) {
if (this.events[event]) {
this.events[event] = this.events[event].filter(
listener => listener !== listenerToRemove
);
}
}
}
const emitter = new EventEmitter();
emitter.on('data', data => console.log('Received:', data));
emitter.emit('data', { id: 1 }); // Received: {id: 1}
8.3 策略模式
使用class实现可替换的算法策略:
javascript复制class PaymentStrategy {
pay(amount) {
throw new Error('pay() method must be implemented');
}
}
class CreditCardStrategy extends PaymentStrategy {
pay(amount) {
console.log(`Paying ${amount} via Credit Card`);
}
}
class PayPalStrategy extends PaymentStrategy {
pay(amount) {
console.log(`Paying ${amount} via PayPal`);
}
}
class ShoppingCart {
constructor() {
this.strategy = null;
this.amount = 0;
}
setPaymentStrategy(strategy) {
this.strategy = strategy;
}
checkout() {
if (!this.strategy) {
throw new Error('Payment strategy not set');
}
this.strategy.pay(this.amount);
}
}
const cart = new ShoppingCart();
cart.amount = 100;
cart.setPaymentStrategy(new CreditCardStrategy());
cart.checkout(); // Paying 100 via Credit Card
9. TypeScript中的类增强
TypeScript为class提供了额外的类型安全特性:
typescript复制class Point {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
distance(other: Point): number {
const dx = this.x - other.x;
const dy = this.y - other.y;
return Math.sqrt(dx * dx + dy * dy);
}
}
interface Drawable {
draw(): void;
}
class Circle extends Point implements Drawable {
radius: number;
constructor(x: number, y: number, radius: number) {
super(x, y);
this.radius = radius;
}
draw() {
console.log(`Drawing circle at (${this.x}, ${this.y}) with radius ${this.radius}`);
}
}
TypeScript还支持:
- 访问修饰符(public, private, protected)
- 抽象类
- 接口实现
- 参数属性等特性
10. 现代JavaScript框架中的类应用
10.1 React类组件
虽然React现在推荐使用函数组件,但类组件仍然广泛存在:
javascript复制class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState(prevState => ({ count: prevState.count + 1 }));
};
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
10.2 Angular中的类使用
Angular重度依赖class语法:
typescript复制import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'my-app';
onClick() {
console.log('Button clicked');
}
}
10.3 Node.js中的类应用
在Node.js中,class常用于组织业务逻辑:
javascript复制const fs = require('fs').promises;
class FileService {
constructor(directory) {
this.directory = directory;
}
async readFile(filename) {
const path = `${this.directory}/${filename}`;
return await fs.readFile(path, 'utf-8');
}
async writeFile(filename, content) {
const path = `${this.directory}/${filename}`;
await fs.writeFile(path, content);
}
}
const fileService = new FileService('./data');
fileService.writeFile('test.txt', 'Hello World');
