TypeScript 类的静态成员与静态方法

本文献给:

已掌握 TypeScript 类基础、继承、多态、抽象类等知识的开发者。本文将带你学习类的静态成员(static 属性)和静态方法,包括访问限制、与实例成员的区别,以及工具类设计中的典型应用。

你将学到:

  1. 静态属性与静态方法的定义
  2. 静态成员与实例成员的区别
  3. 静态成员的访问限制(public/private/protected
  4. 静态成员在继承中的行为
  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
    }
}

三、静态成员的访问修饰符

静态成员可以结合 publicprivateprotected 使用,控制访问范围。

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 #静态成员 #静态方法 #面向对象 #学习笔记 #前端开发

相关推荐
用户440145493141936 分钟前
Spring Boot 3.x 异步编程实战:从 @Async 到虚拟线程
javascript
charlie1145141911 小时前
RK3506B: buildroot:出一份正规的最小 rootfs
开发语言·嵌入式·开源项目·rk3506b
Byron Loong1 小时前
【c#】Bitmap释放之 大象与蚊子
开发语言·c#
音符犹如代码2 小时前
Java动态线程池:避坑原生线程池,吃透Dynamic-TP,手写一个Demo
java·开发语言
喜欢就别2 小时前
平均风险:Rényi DP 和零集中 DP
开发语言·r语言
无情的西瓜皮2 小时前
MCP 协议实战:从零搭建一个 MCP 服务器(Node.js 版)
vue.js·人工智能·typescript·node.js
wangruofeng2 小时前
终端里 rm 一下文件就没了,macOS 怎么删文件才进废纸篓
javascript·命令行·apple
小妖6662 小时前
React input 输入卡顿问题
前端·javascript·react.js
无足鸟ICT2 小时前
【RHCA+】bash命令
linux·开发语言·bash
方华世界3 小时前
企业级Java AI Agent应用平台
java·开发语言·人工智能