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

相关推荐
郭涤生1 小时前
C++ 高性能编程最佳实践清单
开发语言·c++
Nile1 小时前
解密Palantir系列一:4. Ontology 不是哲学
开发语言·前端·javascript
Highcharts1 小时前
如何创建蛛网地图|气泡事件+全球发布+关联组合图表开发示例
javascript
xier1234561 小时前
three-instance-batch 开发笔记
javascript·three.js
王林不想说话1 小时前
TypeScript 进阶知识总结:从 extends、泛型到 infer,一篇打通 TS 类型系统
前端·javascript·typescript
罗超驿2 小时前
15.JavaScript 函数与作用域完全指南:语法、参数、表达式与作用域链实战
开发语言·前端·javascript
.千余2 小时前
【C++】C++类与对象2:C++构造函数、运算符重载与流输入输出全面解析
c语言·开发语言·前端·c++·经验分享
郭涤生2 小时前
C++ 高性能状态机
开发语言·c++
且听风吟_xincell2 小时前
用 TypeScript 从零写一个 TCP 聊天室(上)—— 网络编程入门实战
网络·tcp/ip·typescript