本文献给:
已掌握 TypeScript 类基础、继承、多态、抽象类等知识的开发者。本文将带你学习类的静态成员(static 属性)和静态方法,包括访问限制、与实例成员的区别,以及工具类设计中的典型应用。
你将学到:
- 静态属性与静态方法的定义
- 静态成员与实例成员的区别
- 静态成员的访问限制(
public/private/protected) - 静态成员在继承中的行为
- 工具类与工厂模式的静态方法设计
目录
- 一、静态成员的定义
- 二、静态方法与实例方法的区别
- 三、静态成员的访问修饰符
-
- [3.1 protected 静态成员](#3.1 protected 静态成员)
- 四、静态成员在继承中的行为
-
- [4.1 类名与 this 的区别](#4.1 类名与 this 的区别)
- 五、常见使用场景
-
- [5.1 工具类](#5.1 工具类)
- [5.2 工厂方法](#5.2 工厂方法)
- [5.3 单例模式](#5.3 单例模式)
- 六、常见错误与注意事项
-
- [6.1 静态方法中访问实例成员](#6.1 静态方法中访问实例成员)
- [6.2 实例中访问静态成员时混淆](#6.2 实例中访问静态成员时混淆)
- [6.3 子类覆盖静态属性时影响父类静态方法中的 this](#6.3 子类覆盖静态属性时影响父类静态方法中的 this)
- [6.4 在静态块中初始化(ES2022+)](#6.4 在静态块中初始化(ES2022+))
- [6.5 泛型类中的静态成员](#6.5 泛型类中的静态成员)
- 七、综合示例
- 八、小结
一、静态成员的定义
使用 static 关键字定义类的静态属性和静态方法。静态成员属于类本身,而不是类的实例。
typescript
class Circle {
static pi: number = 3.14159;
static calculateArea(radius: number): number {
return this.pi * radius * radius;
}
radius: number;
constructor(radius: number) {
this.radius = radius;
}
getArea(): number {
return Circle.calculateArea(this.radius);
}
}
console.log(Circle.pi); // 3.14159
console.log(Circle.calculateArea(5)); // 78.53975
const c = new Circle(5);
console.log(c.getArea()); // 78.53975
// console.log(c.pi); // ❌ 实例不能访问静态属性
静态成员通过类名直接访问,实例无法访问静态成员(但可以通过 this.constructor 间接访问)。
二、静态方法与实例方法的区别
| 特性 | 静态方法 | 实例方法 |
|---|---|---|
| 归属 | 类本身 | 类的实例 |
| 调用方式 | ClassName.method() |
instance.method() |
| 访问实例成员 | 不能直接访问(无 this 指向实例) |
可以访问实例成员 |
| 访问静态成员 | 可以(通过 this 或类名) |
可以(通过类名) |
| 使用场景 | 工具函数、工厂方法、单例模式 | 操作实例数据 |
typescript
class Example {
static staticProp = 0;
instanceProp = 1;
static staticMethod() {
console.log(this.staticProp); // OK
// console.log(this.instanceProp); // ❌ 静态方法中不能访问实例属性
}
instanceMethod() {
console.log(Example.staticProp); // OK
console.log(this.instanceProp); // OK
}
}
三、静态成员的访问修饰符
静态成员可以结合 public、private、protected 使用,控制访问范围。
typescript
class Database {
private static instance: Database;
private constructor() {}
static getInstance(): Database {
if (!Database.instance) {
Database.instance = new Database();
}
return Database.instance;
}
query(sql: string) {
console.log(`Executing: ${sql}`);
}
}
const db = Database.getInstance();
db.query("SELECT * FROM users");
// const db2 = new Database(); // ❌ 构造函数私有
3.1 protected 静态成员
protected static 可以在子类中访问。
typescript
class Base {
protected static config = { version: "1.0" };
}
class Derived extends Base {
static showConfig() {
console.log(this.config); // OK
}
}
Derived.showConfig(); // { version: "1.0" }
四、静态成员在继承中的行为
静态成员也会被继承,子类可以访问父类的静态成员。
typescript
class Parent {
static value = 10;
static getValue() {
return this.value;
}
}
class Child extends Parent {
static value = 20; // 覆盖
}
console.log(Parent.getValue()); // 10
console.log(Child.getValue()); // 20(静态方法中的 this 指向调用者)
静态方法中的 this 指向调用该方法的类(而不是定义时的类),因此子类可以覆盖静态属性并影响方法返回值。
4.1 类名与 this 的区别
typescript
class A {
static name = "A";
static getName() {
return this.name;
}
static getNameHard() {
return A.name; // 始终返回 A.name
}
}
class B extends A {
static name = "B";
}
console.log(B.getName()); // "B"(this 指向 B)
console.log(B.getNameHard()); // "A"(固定使用 A.name)
五、常见使用场景
5.1 工具类
将相关工具函数组织为静态方法,无需实例化。
typescript
class MathUtils {
static clamp(value: number, min: number, max: number): number {
return Math.min(max, Math.max(min, value));
}
static randomRange(min: number, max: number): number {
return min + Math.random() * (max - min);
}
static degToRad(deg: number): number {
return deg * Math.PI / 180;
}
}
console.log(MathUtils.clamp(150, 0, 100)); // 100
5.2 工厂方法
静态方法作为工厂创建实例,可以封装复杂的创建逻辑或缓存。
typescript
class User {
private constructor(public id: number, public name: string) {}
private static cache = new Map<number, User>();
static create(id: number, name: string): User {
if (this.cache.has(id)) {
return this.cache.get(id)!;
}
const user = new User(id, name);
this.cache.set(id, user);
return user;
}
}
const u1 = User.create(1, "Alice");
const u2 = User.create(1, "Bob"); // 返回缓存的 Alice
console.log(u1 === u2); // true
5.3 单例模式
确保一个类只有一个实例。
typescript
class Logger {
private static instance: Logger;
private logs: string[] = [];
private constructor() {}
static getInstance(): Logger {
if (!Logger.instance) {
Logger.instance = new Logger();
}
return Logger.instance;
}
log(msg: string) {
this.logs.push(msg);
console.log(msg);
}
getLogs() {
return [...this.logs];
}
}
const logger1 = Logger.getInstance();
const logger2 = Logger.getInstance();
console.log(logger1 === logger2); // true
六、常见错误与注意事项
6.1 静态方法中访问实例成员
typescript
class Demo {
name = "demo";
static test() {
// console.log(this.name); // ❌ 静态方法中 this 是类,没有 name
}
}
如果需要访问实例,可以将实例作为参数传入。
6.2 实例中访问静态成员时混淆
实例方法中访问静态成员推荐使用类名,而不是 this,因为 this 可能被覆盖(尤其在继承中)。
typescript
class Parent {
static value = 10;
getStatic() {
return (this.constructor as any).value; // 不推荐,麻烦且容易出错
}
getStaticBetter() {
return Parent.value; // 明确使用类名
}
}
6.3 子类覆盖静态属性时影响父类静态方法中的 this
如果父类静态方法使用 this.xxx,子类覆盖静态属性后,调用子类该方法会得到子类属性值。这可能符合预期,也可能不是。根据需求选择使用 ClassName 还是 this。
6.4 在静态块中初始化(ES2022+)
TypeScript 支持静态块(需 target ES2022 或更高),用于复杂静态初始化。
typescript
class Config {
static settings: Record<string, string>;
static {
// 静态块在类初始化时执行
this.settings = JSON.parse(localStorage.getItem("config") || "{}");
}
}
6.5 泛型类中的静态成员
静态成员不能引用类的泛型类型参数,因为静态成员属于类而非实例,类型参数在实例化时才确定。
typescript
class Generic<T> {
// static value: T; // ❌ 静态成员不能使用泛型参数
}
七、综合示例
typescript
// 任务管理器:使用静态成员管理全局任务计数和配置
class Task {
private static taskCount = 0;
private static readonly MAX_TASKS = 100;
static get count() {
return Task.taskCount;
}
static canCreate(): boolean {
return Task.taskCount < Task.MAX_TASKS;
}
static reset() {
Task.taskCount = 0;
}
private id: number;
constructor(public title: string) {
if (!Task.canCreate()) {
throw new Error("Task limit reached");
}
this.id = ++Task.taskCount;
}
getId() {
return this.id;
}
}
// 子类继承静态成员
class UrgentTask extends Task {
static override canCreate(): boolean {
return Task.count < 20; // 紧急任务限制更严格
}
constructor(title: string, public priority: number) {
super(title);
}
}
try {
for (let i = 0; i < 50; i++) {
new Task(`Task ${i}`);
}
} catch (e) {
console.log(e.message); // "Task limit reached"
}
console.log(Task.count); // 100
Task.reset();
console.log(Task.count); // 0
// 工厂静态方法
class Point {
constructor(public x: number, public y: number) {}
static fromPolar(radius: number, angle: number): Point {
return new Point(radius * Math.cos(angle), radius * Math.sin(angle));
}
static fromObject(obj: { x: number; y: number }): Point {
return new Point(obj.x, obj.y);
}
}
const p1 = Point.fromPolar(5, Math.PI / 4);
const p2 = Point.fromObject({ x: 10, y: 20 });
console.log(p1, p2);
八、小结
| 概念 | 语法示例 | 说明 |
|---|---|---|
| 静态属性 | static count = 0 |
属于类本身的属性 |
| 静态方法 | static getCount() { return this.count; } |
属于类本身的方法 |
| 访问静态成员 | ClassName.property |
在外部和实例方法中通过类名访问 |
| 继承中的静态成员 | 子类可访问/覆盖父类静态成员 | 静态方法中的 this 指向子类 |
| 私有静态成员 | private static instance |
用于单例模式 |
| 使用场景 | 工具方法、工厂、缓存、单例 | 无需实例化的功能 |
觉得文章有帮助?别忘了:
👍 点赞 👍 -- 给我一点鼓励
⭐ 收藏 ⭐ -- 方便以后查看
🔔 关注 🔔 -- 获取更新通知
标签: #TypeScript #静态成员 #静态方法 #面向对象 #学习笔记 #前端开发