本文献给:

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


你将学到:

  1. 静态属性与静态方法的定义
  2. 静态成员与实例成员的区别
  3. 静态成员的访问限制(public/private/protected
  4. 静态成员在继承中的行为
  5. 工具类与工厂模式的静态方法设计



一、静态成员的定义

使用 static 关键字定义类的静态属性和静态方法。静态成员属于类本身,而不是类的实例。

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 或类名) 可以(通过类名)
使用场景 工具函数、工厂方法、单例模式 操作实例数据
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 使用,控制访问范围。

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 可以在子类中访问。

class Base {
    protected static config = { version: "1.0" };
}

class Derived extends Base {
    static showConfig() {
        console.log(this.config);  // OK
    }
}

Derived.showConfig();  // { version: "1.0" }

四、静态成员在继承中的行为

静态成员也会被继承,子类可以访问父类的静态成员。

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 的区别

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 工具类

将相关工具函数组织为静态方法,无需实例化。

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 工厂方法

静态方法作为工厂创建实例,可以封装复杂的创建逻辑或缓存。

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 单例模式

确保一个类只有一个实例。

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 静态方法中访问实例成员

class Demo {
    name = "demo";
    static test() {
        // console.log(this.name);  // ❌ 静态方法中 this 是类,没有 name
    }
}

如果需要访问实例,可以将实例作为参数传入。

6.2 实例中访问静态成员时混淆

实例方法中访问静态成员推荐使用类名,而不是 this,因为 this 可能被覆盖(尤其在继承中)。

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 或更高),用于复杂静态初始化。

class Config {
    static settings: Record<string, string>;
    static {
        // 静态块在类初始化时执行
        this.settings = JSON.parse(localStorage.getItem("config") || "{}");
    }
}

6.5 泛型类中的静态成员

静态成员不能引用类的泛型类型参数,因为静态成员属于类而非实例,类型参数在实例化时才确定。

class Generic<T> {
    // static value: T;  // ❌ 静态成员不能使用泛型参数
}

七、综合示例

// 任务管理器:使用静态成员管理全局任务计数和配置
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 #静态成员 #静态方法 #面向对象 #学习笔记 #前端开发

更多推荐